summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012
diff options
context:
space:
mode:
Diffstat (limited to 'keyexchange/isakmpd-20041012')
-rw-r--r--keyexchange/isakmpd-20041012/.depend211
-rw-r--r--keyexchange/isakmpd-20041012/BUGS100
-rw-r--r--keyexchange/isakmpd-20041012/DESIGN-NOTES414
-rw-r--r--keyexchange/isakmpd-20041012/GNUmakefile244
-rw-r--r--keyexchange/isakmpd-20041012/Makefile187
-rw-r--r--keyexchange/isakmpd-20041012/QUESTIONS34
-rw-r--r--keyexchange/isakmpd-20041012/README68
-rw-r--r--keyexchange/isakmpd-20041012/README.PKI60
-rw-r--r--keyexchange/isakmpd-20041012/TO-DO145
-rw-r--r--keyexchange/isakmpd-20041012/app.c63
-rw-r--r--keyexchange/isakmpd-20041012/app.h42
-rw-r--r--keyexchange/isakmpd-20041012/apps/Makefile34
-rw-r--r--keyexchange/isakmpd-20041012/apps/certpatch/.cvsignore3
-rw-r--r--keyexchange/isakmpd-20041012/apps/certpatch/GNUmakefile55
-rw-r--r--keyexchange/isakmpd-20041012/apps/certpatch/Makefile58
-rw-r--r--keyexchange/isakmpd-20041012/apps/certpatch/certpatch.885
-rw-r--r--keyexchange/isakmpd-20041012/apps/certpatch/certpatch.c317
-rw-r--r--keyexchange/isakmpd-20041012/attribute.c112
-rw-r--r--keyexchange/isakmpd-20041012/attribute.h47
-rw-r--r--keyexchange/isakmpd-20041012/cert.c160
-rw-r--r--keyexchange/isakmpd-20041012/cert.h96
-rw-r--r--keyexchange/isakmpd-20041012/conf.c1123
-rw-r--r--keyexchange/isakmpd-20041012/conf.h103
-rw-r--r--keyexchange/isakmpd-20041012/connection.c449
-rw-r--r--keyexchange/isakmpd-20041012/connection.h51
-rw-r--r--keyexchange/isakmpd-20041012/constants.c99
-rw-r--r--keyexchange/isakmpd-20041012/constants.h47
-rw-r--r--keyexchange/isakmpd-20041012/cookie.c74
-rw-r--r--keyexchange/isakmpd-20041012/cookie.h44
-rw-r--r--keyexchange/isakmpd-20041012/crypto.c413
-rw-r--r--keyexchange/isakmpd-20041012/crypto.h175
-rw-r--r--keyexchange/isakmpd-20041012/debian/ChangeLog1668
-rw-r--r--keyexchange/isakmpd-20041012/debian/README.Debian17
-rw-r--r--keyexchange/isakmpd-20041012/debian/changelog153
-rw-r--r--keyexchange/isakmpd-20041012/debian/control17
-rw-r--r--keyexchange/isakmpd-20041012/debian/copyright21
-rw-r--r--keyexchange/isakmpd-20041012/debian/isakmpd.dirs13
-rw-r--r--keyexchange/isakmpd-20041012/debian/isakmpd.init32
-rw-r--r--keyexchange/isakmpd-20041012/debian/isakmpd.lintian3
-rwxr-xr-xkeyexchange/isakmpd-20041012/debian/rules73
-rw-r--r--keyexchange/isakmpd-20041012/dh.c82
-rw-r--r--keyexchange/isakmpd-20041012/dh.h43
-rw-r--r--keyexchange/isakmpd-20041012/dnssec.c293
-rw-r--r--keyexchange/isakmpd-20041012/dnssec.h46
-rw-r--r--keyexchange/isakmpd-20041012/doi.c61
-rw-r--r--keyexchange/isakmpd-20041012/doi.h101
-rw-r--r--keyexchange/isakmpd-20041012/dpd.c374
-rw-r--r--keyexchange/isakmpd-20041012/dpd.h38
-rw-r--r--keyexchange/isakmpd-20041012/exchange.c1799
-rw-r--r--keyexchange/isakmpd-20041012/exchange.h252
-rw-r--r--keyexchange/isakmpd-20041012/exchange_num.cst42
-rw-r--r--keyexchange/isakmpd-20041012/features/aggressive32
-rw-r--r--keyexchange/isakmpd-20041012/features/dnssec30
-rw-r--r--keyexchange/isakmpd-20041012/features/dpd27
-rw-r--r--keyexchange/isakmpd-20041012/features/ec32
-rw-r--r--keyexchange/isakmpd-20041012/features/isakmp_cfg31
-rw-r--r--keyexchange/isakmpd-20041012/features/nat_traversal27
-rw-r--r--keyexchange/isakmpd-20041012/features/policy33
-rw-r--r--keyexchange/isakmpd-20041012/features/privsep27
-rw-r--r--keyexchange/isakmpd-20041012/features/x50932
-rw-r--r--keyexchange/isakmpd-20041012/field.c252
-rw-r--r--keyexchange/isakmpd-20041012/field.h54
-rw-r--r--keyexchange/isakmpd-20041012/genconstants.sh114
-rw-r--r--keyexchange/isakmpd-20041012/genfields.sh185
-rw-r--r--keyexchange/isakmpd-20041012/gmp_util.c105
-rw-r--r--keyexchange/isakmpd-20041012/gmp_util.h42
-rw-r--r--keyexchange/isakmpd-20041012/hash.c145
-rw-r--r--keyexchange/isakmpd-20041012/hash.h70
-rw-r--r--keyexchange/isakmpd-20041012/if.c152
-rw-r--r--keyexchange/isakmpd-20041012/if.h43
-rw-r--r--keyexchange/isakmpd-20041012/ike_aggressive.c184
-rw-r--r--keyexchange/isakmpd-20041012/ike_aggressive.h40
-rw-r--r--keyexchange/isakmpd-20041012/ike_auth.c1167
-rw-r--r--keyexchange/isakmpd-20041012/ike_auth.h48
-rw-r--r--keyexchange/isakmpd-20041012/ike_main_mode.c124
-rw-r--r--keyexchange/isakmpd-20041012/ike_main_mode.h40
-rw-r--r--keyexchange/isakmpd-20041012/ike_phase_1.c1396
-rw-r--r--keyexchange/isakmpd-20041012/ike_phase_1.h53
-rw-r--r--keyexchange/isakmpd-20041012/ike_quick_mode.c1989
-rw-r--r--keyexchange/isakmpd-20041012/ike_quick_mode.h40
-rw-r--r--keyexchange/isakmpd-20041012/init.c158
-rw-r--r--keyexchange/isakmpd-20041012/init.h38
-rw-r--r--keyexchange/isakmpd-20041012/ipsec.c2523
-rw-r--r--keyexchange/isakmpd-20041012/ipsec.h173
-rw-r--r--keyexchange/isakmpd-20041012/ipsec_doi.h44
-rw-r--r--keyexchange/isakmpd-20041012/ipsec_fld.fld60
-rw-r--r--keyexchange/isakmpd-20041012/ipsec_num.cst264
-rw-r--r--keyexchange/isakmpd-20041012/isakmp.h64
-rw-r--r--keyexchange/isakmpd-20041012/isakmp_cfg.c982
-rw-r--r--keyexchange/isakmpd-20041012/isakmp_cfg.h53
-rw-r--r--keyexchange/isakmpd-20041012/isakmp_doi.c264
-rw-r--r--keyexchange/isakmpd-20041012/isakmp_doi.h37
-rw-r--r--keyexchange/isakmpd-20041012/isakmp_fld.fld164
-rw-r--r--keyexchange/isakmpd-20041012/isakmp_num.cst264
-rw-r--r--keyexchange/isakmpd-20041012/isakmpd.8603
-rw-r--r--keyexchange/isakmpd-20041012/isakmpd.c543
-rw-r--r--keyexchange/isakmpd-20041012/isakmpd.conf.51126
-rw-r--r--keyexchange/isakmpd-20041012/isakmpd.policy.5638
-rw-r--r--keyexchange/isakmpd-20041012/key.c213
-rw-r--r--keyexchange/isakmpd-20041012/key.h39
-rw-r--r--keyexchange/isakmpd-20041012/libcrypto.c49
-rw-r--r--keyexchange/isakmpd-20041012/libcrypto.h52
-rw-r--r--keyexchange/isakmpd-20041012/log.c706
-rw-r--r--keyexchange/isakmpd-20041012/log.h102
-rw-r--r--keyexchange/isakmpd-20041012/math_2n.c1107
-rw-r--r--keyexchange/isakmpd-20041012/math_2n.h132
-rw-r--r--keyexchange/isakmpd-20041012/math_ec2n.c382
-rw-r--r--keyexchange/isakmpd-20041012/math_ec2n.h94
-rw-r--r--keyexchange/isakmpd-20041012/math_group.c865
-rw-r--r--keyexchange/isakmpd-20041012/math_group.h94
-rw-r--r--keyexchange/isakmpd-20041012/math_mp.h56
-rw-r--r--keyexchange/isakmpd-20041012/message.c2530
-rw-r--r--keyexchange/isakmpd-20041012/message.h205
-rw-r--r--keyexchange/isakmpd-20041012/monitor.c1174
-rw-r--r--keyexchange/isakmpd-20041012/monitor.h104
-rw-r--r--keyexchange/isakmpd-20041012/monitor_fdpass.c112
-rw-r--r--keyexchange/isakmpd-20041012/nat_traversal.c439
-rw-r--r--keyexchange/isakmpd-20041012/nat_traversal.h55
-rw-r--r--keyexchange/isakmpd-20041012/pf_key_v2.c4442
-rw-r--r--keyexchange/isakmpd-20041012/pf_key_v2.h61
-rw-r--r--keyexchange/isakmpd-20041012/policy.c2318
-rw-r--r--keyexchange/isakmpd-20041012/policy.h70
-rw-r--r--keyexchange/isakmpd-20041012/prf.c161
-rw-r--r--keyexchange/isakmpd-20041012/prf.h58
-rw-r--r--keyexchange/isakmpd-20041012/regress/Makefile34
-rw-r--r--keyexchange/isakmpd-20041012/regress/b2n/.cvsignore2
-rw-r--r--keyexchange/isakmpd-20041012/regress/b2n/Makefile16
-rw-r--r--keyexchange/isakmpd-20041012/regress/b2n/b2ntest.c368
-rw-r--r--keyexchange/isakmpd-20041012/regress/check.sh88
-rw-r--r--keyexchange/isakmpd-20041012/regress/crypto/.cvsignore2
-rw-r--r--keyexchange/isakmpd-20041012/regress/crypto/Makefile20
-rw-r--r--keyexchange/isakmpd-20041012/regress/crypto/cryptotest.c178
-rw-r--r--keyexchange/isakmpd-20041012/regress/dh/.cvsignore2
-rw-r--r--keyexchange/isakmpd-20041012/regress/dh/Makefile29
-rw-r--r--keyexchange/isakmpd-20041012/regress/dh/dhtest.c102
-rw-r--r--keyexchange/isakmpd-20041012/regress/ec2n/.cvsignore2
-rw-r--r--keyexchange/isakmpd-20041012/regress/ec2n/Makefile16
-rw-r--r--keyexchange/isakmpd-20041012/regress/ec2n/ec2ntest.c144
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/.cvsignore1
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/Makefile58
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/README78
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/def-i.1bin0 -> 72 bytes
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/def-r.1bin0 -> 72 bytes
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/mm-1-setup.sh12
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/mm-i-1.t43
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/mm-r-1.t42
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/run.pl105
-rw-r--r--keyexchange/isakmpd-20041012/regress/exchange/run.sh137
-rw-r--r--keyexchange/isakmpd-20041012/regress/group/.cvsignore2
-rw-r--r--keyexchange/isakmpd-20041012/regress/group/Makefile29
-rw-r--r--keyexchange/isakmpd-20041012/regress/group/grouptest.c121
-rw-r--r--keyexchange/isakmpd-20041012/regress/hmac/.cvsignore2
-rw-r--r--keyexchange/isakmpd-20041012/regress/hmac/Makefile16
-rw-r--r--keyexchange/isakmpd-20041012/regress/hmac/hmactest.c93
-rw-r--r--keyexchange/isakmpd-20041012/regress/prf/.cvsignore2
-rw-r--r--keyexchange/isakmpd-20041012/regress/prf/Makefile16
-rw-r--r--keyexchange/isakmpd-20041012/regress/prf/prftest.c116
-rw-r--r--keyexchange/isakmpd-20041012/regress/rsakeygen/.cvsignore4
-rw-r--r--keyexchange/isakmpd-20041012/regress/rsakeygen/Makefile83
-rw-r--r--keyexchange/isakmpd-20041012/regress/rsakeygen/rsakeygen.c128
-rw-r--r--keyexchange/isakmpd-20041012/regress/util/Makefile15
-rw-r--r--keyexchange/isakmpd-20041012/regress/util/utiltest.c85
-rw-r--r--keyexchange/isakmpd-20041012/regress/x509/.cvsignore2
-rw-r--r--keyexchange/isakmpd-20041012/regress/x509/Makefile95
-rw-r--r--keyexchange/isakmpd-20041012/regress/x509/x509test.c291
-rw-r--r--keyexchange/isakmpd-20041012/sa.c1247
-rw-r--r--keyexchange/isakmpd-20041012/sa.h318
-rw-r--r--keyexchange/isakmpd-20041012/samples/Makefile34
-rw-r--r--keyexchange/isakmpd-20041012/samples/VPN-3way-template.conf116
-rw-r--r--keyexchange/isakmpd-20041012/samples/VPN-east.conf50
-rw-r--r--keyexchange/isakmpd-20041012/samples/VPN-west.conf50
-rw-r--r--keyexchange/isakmpd-20041012/samples/policy10
-rw-r--r--keyexchange/isakmpd-20041012/samples/singlehost-east.conf64
-rw-r--r--keyexchange/isakmpd-20041012/samples/singlehost-east.gdb1
-rw-r--r--keyexchange/isakmpd-20041012/samples/singlehost-setup.sh84
-rw-r--r--keyexchange/isakmpd-20041012/samples/singlehost-west.conf64
-rw-r--r--keyexchange/isakmpd-20041012/samples/singlehost-west.gdb1
-rw-r--r--keyexchange/isakmpd-20041012/sysdep.h84
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/bsdi/GNUmakefile.sysdep64
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/bsdi/Makefile.sysdep79
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep-os.h66
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep.c225
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/blf.h70
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/cast.h22
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/GNUmakefile57
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/Makefile43
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/arc4random.c178
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/blowfish.c685
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/cast.c778
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/md5.c392
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/sha1.c173
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcat.c62
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcpy.c58
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/md5.h73
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/pcap.h69
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/common/sha1.h18
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/darwin/GNUmakefile.sysdep48
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/darwin/Makefile.sysdep45
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/darwin/sysdep-os.h81
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/darwin/sysdep.c223
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freebsd/GNUmakefile.sysdep61
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freebsd/Makefile.sysdep77
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep-os.h79
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep.c228
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freeswan/GNUmakefile.sysdep72
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freeswan/Makefile.sysdep75
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freeswan/README16
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freeswan/klips.c662
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freeswan/klips.h51
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freeswan/sys/queue.h333
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep-os.h46
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep.c186
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/linux/GNUmakefile.sysdep60
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/linux/bitstring.h128
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/linux/include/bitstring.h132
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/linux/include/sys/queue.h453
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/linux/sys/queue.h499
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/linux/sysdep-os.h64
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/linux/sysdep.c226
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/netbsd/GNUmakefile.sysdep63
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/netbsd/Makefile.sysdep79
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep-os.h51
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep.c225
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/openbsd/GNUmakefile.sysdep52
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/openbsd/Makefile.sysdep52
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/openbsd/keynote_compat.c82
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep-os.h89
-rw-r--r--keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep.c266
-rw-r--r--keyexchange/isakmpd-20041012/timer.c139
-rw-r--r--keyexchange/isakmpd-20041012/timer.h55
-rw-r--r--keyexchange/isakmpd-20041012/transport.c431
-rw-r--r--keyexchange/isakmpd-20041012/transport.h159
-rw-r--r--keyexchange/isakmpd-20041012/udp.c573
-rw-r--r--keyexchange/isakmpd-20041012/udp.h52
-rw-r--r--keyexchange/isakmpd-20041012/udp_encap.c473
-rw-r--r--keyexchange/isakmpd-20041012/udp_encap.h37
-rw-r--r--keyexchange/isakmpd-20041012/ui.c528
-rw-r--r--keyexchange/isakmpd-20041012/ui.h45
-rw-r--r--keyexchange/isakmpd-20041012/util.c485
-rw-r--r--keyexchange/isakmpd-20041012/util.h70
-rw-r--r--keyexchange/isakmpd-20041012/virtual.c722
-rw-r--r--keyexchange/isakmpd-20041012/virtual.h42
-rw-r--r--keyexchange/isakmpd-20041012/x509.c1439
-rw-r--r--keyexchange/isakmpd-20041012/x509.h90
-rw-r--r--keyexchange/isakmpd-20041012/x509v3.cnf26
245 files changed, 58357 insertions, 0 deletions
diff --git a/keyexchange/isakmpd-20041012/.depend b/keyexchange/isakmpd-20041012/.depend
new file mode 100644
index 0000000..42dbda6
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/.depend
@@ -0,0 +1,211 @@
+app.o: app.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ app.h log.h
+attribute.o: attribute.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ attribute.h conf.h log.h isakmp.h isakmp_fld.h field.h isakmp_num.h \
+ constants.h util.h
+cert.o: cert.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ isakmp_num.h constants.h log.h cert.h
+connection.o: connection.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ conf.h connection.h doi.h ipsec.h ipsec_doi.h ipsec_fld.h field.h \
+ ipsec_num.h constants.h isakmp.h isakmp_fld.h isakmp_num.h log.h \
+ timer.h util.h
+constants.o: constants.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ constants.h
+conf.o: conf.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ app.h conf.h log.h util.h
+cookie.o: cookie.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ cookie.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \
+ field.h isakmp_num.h hash.h transport.h message.h util.h
+crypto.o: crypto.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ crypto.h log.h
+dh.o: dh.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ math_group.h dh.h log.h
+doi.o: doi.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ doi.h
+exchange.o: exchange.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ cert.h conf.h connection.h constants.h cookie.h crypto.h doi.h \
+ exchange.h exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h \
+ ipsec_num.h libcrypto.h log.h message.h timer.h transport.h ipsec.h \
+ ipsec_doi.h ipsec_fld.h sa.h util.h key.h
+exchange_num.o: exchange_num.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ constants.h exchange_num.h
+field.o: field.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ constants.h field.h log.h util.h
+gmp_util.o: gmp_util.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ gmp_util.h math_mp.h
+hash.o: hash.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ hash.h log.h
+if.o: if.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ log.h if.h
+ike_auth.o: ike_auth.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ cert.h conf.h constants.h exchange.h exchange_num.h isakmp.h \
+ isakmp_fld.h field.h isakmp_num.h gmp_util.h math_mp.h hash.h \
+ ike_auth.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h libcrypto.h \
+ log.h message.h prf.h transport.h util.h key.h
+ike_main_mode.o: ike_main_mode.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \
+ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \
+ ike_auth.h ike_main_mode.h ike_phase_1.h ipsec.h ipsec_doi.h \
+ ipsec_fld.h ipsec_num.h log.h math_group.h message.h prf.h sa.h \
+ transport.h util.h
+ike_phase_1.o: ike_phase_1.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \
+ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \
+ ike_auth.h ike_phase_1.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h \
+ log.h math_group.h message.h prf.h sa.h transport.h util.h
+ike_quick_mode.o: ike_quick_mode.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ attribute.h conf.h connection.h dh.h doi.h exchange.h exchange_num.h \
+ constants.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \
+ ike_quick_mode.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h log.h \
+ math_group.h message.h policy.h prf.h sa.h transport.h util.h key.h
+init.o: init.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ app.h cert.h conf.h connection.h doi.h exchange.h exchange_num.h \
+ constants.h isakmp.h isakmp_fld.h field.h isakmp_num.h init.h ipsec.h \
+ ipsec_doi.h ipsec_fld.h ipsec_num.h isakmp_doi.h libcrypto.h log.h \
+ math_group.h sa.h timer.h transport.h message.h udp.h ui.h util.h
+ipsec.o: ipsec.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \
+ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \
+ ike_aggressive.h ike_auth.h ike_main_mode.h ike_quick_mode.h ipsec.h \
+ ipsec_doi.h ipsec_fld.h ipsec_num.h isakmp_cfg.h log.h math_group.h \
+ message.h prf.h sa.h timer.h transport.h util.h x509.h libcrypto.h
+ipsec_fld.o: ipsec_fld.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ constants.h field.h ipsec_fld.h isakmp_num.h ipsec_num.h
+ipsec_num.o: ipsec_num.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ constants.h ipsec_num.h
+isakmpd.o: isakmpd.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ app.h conf.h connection.h init.h libcrypto.h log.h sa.h isakmp.h \
+ isakmp_fld.h field.h isakmp_num.h constants.h timer.h transport.h \
+ message.h udp.h ui.h util.h cert.h
+isakmp_doi.o: isakmp_doi.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ doi.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \
+ field.h isakmp_num.h isakmp_doi.h ipsec.h ipsec_doi.h ipsec_fld.h \
+ ipsec_num.h log.h message.h sa.h util.h
+isakmp_fld.o: isakmp_fld.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ constants.h field.h isakmp_fld.h isakmp_num.h ipsec_num.h
+isakmp_num.o: isakmp_num.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ constants.h isakmp_num.h
+key.o: key.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ key.h libcrypto.h log.h util.h x509.h
+libcrypto.o: libcrypto.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ libcrypto.h
+log.o: log.c sysdep/common/pcap.h isakmp_num.h sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ constants.h log.h
+message.o: message.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ attribute.h cert.h constants.h crypto.h doi.h exchange.h \
+ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h ipsec_num.h \
+ log.h message.h sa.h timer.h transport.h util.h
+math_2n.o: math_2n.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ math_2n.h util.h
+math_group.o: math_group.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ gmp_util.h math_mp.h log.h math_2n.h math_ec2n.h math_group.h
+prf.o: prf.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ hash.h log.h prf.h
+sa.o: sa.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ connection.h cookie.h doi.h exchange.h exchange_num.h constants.h \
+ isakmp.h isakmp_fld.h field.h isakmp_num.h log.h message.h sa.h \
+ timer.h transport.h util.h cert.h policy.h key.h ipsec.h ipsec_doi.h \
+ ipsec_fld.h ipsec_num.h
+sysdep.o: \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep.c \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/app.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/conf.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_doi.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_fld.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/field.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_num.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/constants.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/log.h
+timer.o: timer.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ log.h timer.h
+transport.o: transport.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ conf.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \
+ field.h isakmp_num.h log.h message.h sa.h timer.h transport.h
+udp.o: udp.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ conf.h if.h isakmp.h isakmp_fld.h field.h isakmp_num.h constants.h \
+ log.h message.h transport.h udp.h util.h
+ui.o: ui.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ conf.h connection.h doi.h exchange.h exchange_num.h constants.h \
+ isakmp.h isakmp_fld.h field.h isakmp_num.h init.h log.h sa.h timer.h \
+ transport.h message.h ui.h util.h
+util.o: util.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ log.h message.h isakmp.h isakmp_fld.h field.h isakmp_num.h \
+ constants.h transport.h util.h
+klips.o: \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.c \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/conf.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/exchange.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/exchange_num.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/constants.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp_fld.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/field.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp_num.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/hash.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_doi.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_fld.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_num.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/log.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sa.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/timer.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/transport.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/message.h
+math_ec2n.o: ./math_ec2n.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ math_2n.h math_ec2n.h
+ike_aggressive.o: ./ike_aggressive.c sysdep.h \
+ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \
+ attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \
+ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \
+ ike_auth.h ike_aggressive.h ike_phase_1.h ipsec.h ipsec_doi.h \
+ ipsec_fld.h ipsec_num.h log.h math_group.h message.h prf.h sa.h \
+ transport.h util.h
diff --git a/keyexchange/isakmpd-20041012/BUGS b/keyexchange/isakmpd-20041012/BUGS
new file mode 100644
index 0000000..170282c
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/BUGS
@@ -0,0 +1,100 @@
+$OpenBSD: BUGS,v 1.14 2002/06/09 08:13:06 todd Exp $
+$EOM: BUGS,v 1.38 2000/02/18 08:47:35 niklas Exp $
+
+Until we have a bug-tracking system setup, we might just add bugs to this
+file:
+------------------------------------------------------------------------------
+* message_drop frees the message, this is sometimes wrong and can cause
+ duplicate frees, for example when a proposal does not get chosen. [fixed]
+
+* Notifications should be their own exchanges, otherwise the IV gets
+ disturbed. [fixed]
+
+* We need a death timeout on half-ready SAs just like exchanges. At the
+ moment we leak SAs.
+
+* When we establish a phase 2 exchange we seem to get the wrong IV set,
+ according to SSH's logs. [fixed]
+
+* If a phase 1 SA negotiation terminates with a cause that is to be sent in
+ a NOTIFY to the peer, we get multiple free calls on the cleanup of the
+ informational exchange. [fixed]
+
+* IKE mandates that a HASH should be added to informational exchanges in
+ phase 2. [fixed]
+
+* Message_send requires an exchange to exist, and potentially it tries to
+ encrypt a message multiple times when retransmitting. [fixed]
+
+* Multiple protocol proposals seems to fail. [fixed]
+
+* The initiator fails to match the responders choice of protocol suite with
+ the correct one of its own when several are offered. [fixed]
+
+* Duplicate specified sections is not detected. [fixed]
+
+* Quick mode establishments via UI using -P bind-addr gets "Address already in
+ use".
+
+* Not chosen proposals should be deleted from the protos list in the sa
+ structure. [fixed]
+
+* Setting SPIs generates "Invalid argument" errors due to one tunnel endpoint
+ being INADDR_ANY. [fixed]
+
+* ipsec_proto structs are never allocated. [fixed]
+
+* Remove SPIs of unused proposals. [fixed]
+
+* If the first proposal is turned down, the initiator gets confused.
+
+* Renegotiation after a failed phase 1 fails.
+
+* Phase 1 rekey event removal seems to be done twice. [fixed]
+
+* PF_ENCAP expirations does not find the proper phase 2 SA to remove. [fixed]
+
+* ISAKMP SA expirations should have a soft/hard timeout just like IPsec ones.
+ The soft one should put a watchdog on the SA, and start a renegotiation as
+ soon as something used the SA. Hard ones should just clean it up, no
+ renegotiation at all. [fixed]
+
+* ISAKMP SAs does not get removed after rekeying. [fixed]
+
+* On-demand PF_ENCAP SAs does not get reestablished. [fixed]
+
+* Rekeying is now done automatically on expirations, it should not. The
+ SAs should be brought up on-demand just like the first time.
+
+* Notifications regarding exchange errors seems to not have the right SPI,
+ at least not in phase 1, in NO_PROPOSAL_CHOSEN.
+
+* Outgoing informational exchanges when we use INVALID_PAYLOAD_TYPE
+ cause a DOI error.
+
+* In Linux select(2) of named pipes seems broken as they will return as
+ readable even when nothing is there after one read has succeeded.
+
+* I have seen INITIAL-CONTACT sent on the second Main Mode.
+
+* When ID mismatches occur, coredumps may follow, investigate!
+
+* ESP+AH does not work properly
+
+* Looping QM seen (due to lost sendpackets from other participant?)
+
+* Teardown from UI does not remove exchanges.
+
+* Wrong error message when policy check fails.
+
+* Restransmit of QM (packet 1) after INFO/PAYLOAD_MALFORMED was received.
+
+* SIGSEGV after sa_enter: sa added to sa list, trigged by DELETE notify (Linux)
+
+* Passive connections, undefined local&remote IDs will cause IKE peer IDs
+ to be used.
+
+* host route support in KLIPS does not work properly
+
+* When not having compiled in support for a certain crypto algorithm and
+ the config file still tells us to propose it, we segfault.
diff --git a/keyexchange/isakmpd-20041012/DESIGN-NOTES b/keyexchange/isakmpd-20041012/DESIGN-NOTES
new file mode 100644
index 0000000..b47e80b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/DESIGN-NOTES
@@ -0,0 +1,414 @@
+$OpenBSD: DESIGN-NOTES,v 1.22 2003/06/04 07:27:31 ho Exp $
+$EOM: DESIGN-NOTES,v 1.48 1999/08/12 22:34:25 niklas Exp $
+
+General coding conventions
+--------------------------
+GNU indentation, Max 80 characters per line, KNF comments, mem* instead of b*,
+BSD copyright, one header per module specifying the API.
+Multiple inclusion protection like this:
+
+#ifndef _HEADERNAME_H_
+#define _HEADERNAME_H_
+
+... Here comes the bulk of the header ...
+
+#endif /* _HEADERNAME_H_ */
+
+Start all files with RCS ID tags.
+
+GCC -Wall clean, ANSI prototypes. System dependent facilities should be
+named sysdep_* and be placed in sysdep.c. Every C file should include
+sysdep.h as the first isakmpd include file. Primary target systems are OpenBSD
+and Linux, but porting to Microsoft Windows variants should not be made
+overly difficult.
+
+Note places which need reconsiderations with comments starting with the
+string "XXX", e.g.
+
+/* XXX Not implemented yet. */
+
+TOC
+---
+app.c Application support.
+attribute.c Attribute handling.
+cert.c Dispatching certificate related functions to the according
+ module based on the encoding.
+conf.c Interface to isakmpd configuration.
+connection.c Handle the high-level connection concept.
+constants.c Value to name map of constants.
+cookie.c Cookie generation.
+crypto.c Generic cryptography.
+dh.c Diffie-Hellman exchange logic.
+dnssec.c IKE authentication using signed DNS KEY RRs.
+doi.c Generic handling of different DOIs.
+exchange.c Exchange state machinery.
+exchange_num.cst
+ Some constants used for exhange scripts.
+field.c Generic handling of fields.
+genconstants.sh
+ Generate constant files from .cst source.
+genfields.sh Generate field description files from .fld source.
+gmp_util.c Utilities to ease interfaceing to GMP.
+hash.c Generic hash handling.
+if.c Network interface details.
+ike_aggressive.c
+ IKE's aggressive mode exchange logic.
+ike_auth.c IKE authentication method abstraction.
+ike_main_mode.c IKE's main mode exchange logic.
+ike_phase_1.c Common parts IKE's main & aggressive modes' exchange logic.
+ike_quick_mode.c
+ IKE's quick mode logic.
+init.c Initialization of all modules (might be autogenned in the
+ future).
+ipsec.c The IPsec DOI.
+ipsec_fld.fld Description of IPsec DOI-specific packet layouts.
+ipsec_num.cst Constants defined by the IPsec DOI.
+isakmp_doi.c The ISAKMP pseudo-DOI.
+isakmp_fld.fld Generic packet layout.
+isakmp_num.cst ISAKMP constants.
+isakmpd.c Main loop.
+key.c Generic key handling.
+libcrypto.c Initialize crypto (OpenSSL).
+log.c Logging of exceptional or informational messages.
+math_2n.c Polynomial math.
+math_ec2n.c Elliptic curve math.
+math_group.c Group math.
+message.c Generic message handling.
+pf_key_v2.c Interface with PF_KEY sockets (for use with IPsec).
+policy.c Keynote glue.
+prf.c Pseudo random functions.
+sa.c Handling of Security Associations (SAs).
+sysdep/*/sysdep.c
+ System dependent stuff.
+timer.c Timed events.
+transport.c Generic transport handling.
+udp.c The UDP transport.
+ui.c The "User Interface", i.e. the FIFO command handler.
+util.c Miscellaneous utility functions.
+x509.c Encoding/Decoding X509 Certificates and related structures.
+
+Central datatypes
+-----------------
+
+struct connection Persistent connections.
+struct constant_map A map from constants to their ASCII names.
+struct crypto_xf A crypto class
+struct doi The DOI function switch
+struct event An event that is to happen at some point in time.
+struct exchange A description of an exchange while it is performed.
+struct field A description of an ISAKMP field.
+struct group A class abstracting out Oakley group operations
+struct hash A hashing class
+struct ipsec_exch IPsec-specific exchange fields.
+struct ipsec_proto IPsec-specific protocol attributes.
+struct ipsec_sa IPsec-specific SA stuff.
+struct message A generic ISAKMP message.
+struct payload A "fat" payload reference pointing into message buffers
+struct prf A pseudo random function class
+struct proto Per-protocol attributes.
+struct post_send Post-send function chain node.
+struct sa A security association.
+struct transport An ISAKMP transport, i.e. a channel where ISAKMP
+ messages are passed (not necessarily connection-
+ oriented). This is an abstract class, serving as
+ a superclass to the different specific transports.
+
+SAs & exchanges
+---------------
+
+struct exchange Have all fields belonging to a simple exchange
+ + a list of all the SAs being negotiated.
+ Short-lived.
+struct sa Only hold SA-specific stuff. Lives longer.
+
+In order to recognize exchanges and SAs it is good to know what constitutes
+their identities:
+
+Phase 1 exchange Cookie pair (apart from the first message of course,
+ where the responder cookie is zero.
+
+ISAKMP SA Cookie pair. I.e. there exists a one-to-one
+ mapping to the negotiation in this case.
+
+Phase 2 exchange Cookie pair + message ID.
+
+Generic SA Cookie pair + message ID + SPI.
+
+However it would be really nice to have a name of any SA that is natural
+to use for human beings, for things like deleting SAs manually. The simplest
+ID would be the struct sa address. Another idea would be some kind of sequence
+number, either global or per-destination. Right now I have introduced a name
+for SAs, non-unique, that binds together SAs and their configuration
+parameters. This means both manual exchange runs and rekeying are simpler.
+Both struct exchange and struct sa does hold a reference count, but this is
+not entirely like a reference count in the traditional meaning where
+every reference gets counted. Perhaps it will be in the future, but for now
+we increment the count at allocation time and at times we schedule events
+tha might happen sometime in the future where we will need the structure.
+These events then realeases its reference when done. This way intermediate
+deallocation of these structures are OK.
+
+The basic idea of control flow
+------------------------------
+
+The main loop just waits for events of any kind. Supposedly a message
+comes in, then the daemon looks to see if the cookies describes an
+existing ISAKMP SA, if they don't and the rcookie is zero, it triggers a
+setup of a new ISAKMP SA. An exhaustive validation phase of the message
+is gone through at this stage. If anything goes wrong, we drop the packet
+and probably send some notification back. After the SA is found we try to
+locate the exchange object and advance its state, else we try to create a
+new exchange.
+
+Need exchanges be an abstraction visible in the code? If so an exchange is
+roughly a very simple FSM (only timeouts and retransmissions are events that
+does not just advance the state through a sequential single path). The
+informational exchange is such a special case, I am not sure it's interesting
+to treat as an exchange in the logic of the implementation. The only reason
+to do so would be to keep the implementation tightly coupled to the
+specification for ease of understanding. As the code looks now, exchanges
+*are* an abstraction in the code, and it has proven to be a rather nice
+way of having things.
+
+When the exchange has been found the exchange engine "runs" a script which
+steps forward for each incoming message, and on each reply to them.
+
+Payload parsing details
+-----------------------
+
+After the generic header has been validated, we do a generic payload
+parsing pass over the message and sort out the payloads into buckets indexed
+by the payload type. Note that proposals and transforms are part of the SA
+payloads. We then pass over them once more validating each payload
+in numeric payload type order. This makes SA payloads come naturally first.
+
+Messages
+--------
+
+I am not sure there is any use in sharing the message structure for both
+incoming and outgoing messages but I do it anyhow. Specifically there are
+certain fields which only makes sense in one direction. Incoming messages
+only use one segment in the iovec vector, while outgoing has one segment per
+payload as well as one for the ISAKMP header. The iovec vector is
+reallocated for each payload added, maybe we should do it in chunks of a
+number of payloads instead, like 10 or so.
+
+Design "errors"
+---------------
+
+Currently there are two "errors" in our design. The first one is that the
+coupling between the IPsec DOI and IKE is tight. It should be separated by
+a clean interface letting other key exchange models fit in instead of IKE.
+The second problem is that we need a protocol-specific opaque SA part
+in the DOI specific one. Now both IPsec ESP attributes takes place even
+in ISAKMP SA structures.
+
+User control
+------------
+
+In order to control the daemon you send commands through a FIFO called
+isakmpd.fifo. The commands are one-letter codes followed by arguments.
+For now, eleven such commands are implemented:
+
+c connect Establish a connection with a peer
+C configure Add or remove configuration entries
+d delete Delete an SA given cookies and message-IDs
+D debug Change logging level for a debug class
+p packet capture Enable/disable packet capture feature
+r report Report status information of the daemon
+t teardown Teardown a connection
+Q quit Quit the isakmpd process
+R reinitialize Reinitialize isakmpd (re-read configuration file)
+S report SA Report SA information to file /var/run/isakmp_sa
+T teardown all Teardown all Phase 2 connections
+
+For example you can do:
+
+c ISAKMP-peer
+
+In order to delete an SA you use the 'd' command. However this is not yet
+supported.
+
+To alter the level of debugging in the "LOG_MISC" logging class to 99 you do:
+
+D 0 99
+
+The report command is just an "r", and results in a list of active exchanges
+and security associations.
+
+The "C" command takes 3 subcommands: set, rm and rms, for adding and removing
+entries + remove complete sections respectively. Examples:
+
+C set [Net-A]:Address=192.168.0.0
+C rm [Net-A]:Address
+C rms [Net-A]
+
+All these commands are atomic, i.e. they are not collected into larger
+transactions, which there should be a way to do, but currently isn't.
+
+The FIFO UI is also described in the isakmpd(8) man page.
+
+In addition to giving commands over the FIFO, you may send signals to the
+daemon. Currently two such signals are implemented:
+
+SIGHUP Re-initialize isakmpd (not fully implemented yet)
+SIGUSR1 Generate a report, much as the "r" FIFO command.
+
+For example, to generate a report, you do:
+
+unix# kill -USR1 <PID of isakmpd process>
+
+The constant descriptions
+-------------------------
+
+We have invented a simple constant description language, for the sake
+of easily getting textual representations of manifest constants.
+The syntax is best described by an example:
+
+GROUP
+ CONSTANT_A 1
+ CONSTANT_B 2
+.
+
+This defines a constant map "group" with the following two defines:
+
+#define GROUP_CONSTANT_A 1
+#define GROUP_CONSTANT_B 2
+
+We can now get the textual representation by:
+
+ cp = constant_name (group, foo);
+
+Here foo is an integer with either of the two constants as a value.
+
+The field descriptions
+----------------------
+
+There is language for describing header and payload layouts too,
+similar to the constant descriptions. Here too I just show an example:
+
+RECORD_A
+ FIELD_A raw 4
+ FIELD_B num 2
+ FIELD_C mask 1 group_c_cst
+ FIELD_D ign 1
+ FIELD_E cst 2 group_e1_cst,group_e2_cst
+.
+
+RECORD_B : RECORD_A
+ FIELD_F raw
+.
+
+This creates some utility constants like RECORD_A_SZ, RECORD_A_FIELD_A_LEN,
+RECORD_A_FIELD_A_OFF, RECORD_A_FIELD_B_LEN etc. The *_OFF contains the
+octet offset into the record and the *_LEN constants are the lengths.
+The type fields can be: raw, num, mask, ign & cst. Raw are used for
+octet buffers, num for (unsigned) numbers of 1, 2 or 4 octet's length
+in network byteorder, mask is a bitmask where the bit values have symbols
+coupled to them via the constant maps given after the length in octets
+(also 1, 2 or 4). Ign is just a filler type, ot padding and lastly cst
+denotes constants whose values can be found in the given constant map(s).
+The last field in a record can be a raw, without a length, then just an
+_OFF symbol will be generated. You can offset the first symbol to the
+size of another record, like is done above for RECORD_B, i.e. in that
+case RECORD_A_SZ == RECORD_B_FIELD_F_OFF. All this data are collected
+in struct field arrays which makes it possible to symbolically print out
+entire payloads in readable form via field_dump_payload.
+
+Configuration
+-------------
+
+Internally isakmpd uses a section-tag-value triplet database for
+configuration. Currently this happen to map really well to the
+configuration file format, which on the other hand does not map
+equally well to humans. It is envisioned that the configuration
+database should be dynamically modifiable, and through a lot of
+differnet mechanisms. Therefore we have designed an API for this
+purpose.
+
+int conf_begin ();
+int conf_set (int transaction, char *section, char *tag, char *value,
+ int override);
+int conf_remove (int transaction, char *section, char *tag);
+int conf_remove_section (int transaction, char *section);
+int conf_end (int transaction, int commit);
+
+The caller will always be responsible for the memory management of the
+passed strings, conf_set will copy the values, and not use the original
+strings after it has returned. Return value will be zero on success and
+non-zero otherwise. Note that the conf_remove* functions consider not
+finding anything to remove as failure.
+
+Identification
+--------------
+
+ISAKMP supports a lot of identity types, and we should too of course.
+
+* Phase 1, Main mode or Aggressive mode
+
+Today when we connect we do it based on the peer's IP address. That does not
+automatically mean we should do policy decision based on IPs, rather we should
+look at the ID the peer provide and get policy info keyed on that.
+
+Perhaps we get an ID saying the peer is FQDN niklas.hallqvist.se, then our
+policy rules might look like:
+
+[IQ_FQDN]
+# If commented, internal verification is used
+#Verificator= verify_fqdn
+Accept= no
+
+[ID_FQDN niklas.hallqvist.se]
+Policy= MY_POLICY_001
+
+[MY_POLICY_001]
+# Whatever policy rules we might have.
+Accept= yes
+
+Which means niklas.hallqvist.se is allowed to negotiate SAs with us, but
+noone else.
+
+* Phase 2, Quick mode
+
+In quick mode the identities are implicitly the IP addresses of the peers,
+which must mean the IP addresses actually used for the ISAKMP tunnel.
+Otherwise we today support IPV4_ADDR & IPV4_ADDR_SUBNET as ID types.
+
+X509-Certificates
+-----------------
+To use RSA Signature mode you are required to generate certificates.
+This can be done with ssleay, see man ssl. But the X509 certificates
+require a subjectAltname extension that can either be an IPV4 address,
+a User-FQDN or just FQDN. ssleay can not create those extension,
+insead use the x509test program in regress/x509 to modify an existing
+certificate. It will insert the subjectAltname extension and sign it
+with the provided private Key. The resulting certificate then needs
+to be stored in the directory pointed to by "Certs-directory" in
+section "X509-certificates".
+
+License to use
+--------------
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
diff --git a/keyexchange/isakmpd-20041012/GNUmakefile b/keyexchange/isakmpd-20041012/GNUmakefile
new file mode 100644
index 0000000..838194c
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/GNUmakefile
@@ -0,0 +1,244 @@
+# $OpenBSD: GNUmakefile,v 1.9 2004/08/08 19:11:06 deraadt Exp $
+
+#
+# Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved.
+# Copyright (c) 2000 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+#
+# This makefile is a GNU makefile, which is generally available on most
+# systems, either as "make" or (often) "gmake". It has been converted from
+# a 'pmake' makefile (OpenBSDs 'make'), and some care has been taken to
+# produce similar behaviour.
+#
+
+# openbsd means 2.5 or newer, freeswan is the name for Linux with FreeS/WAN
+# integrated, freebsd/netbsd means FreeBSD/NetBSD with KAME IPsec.
+# darwin means MacOS X 10.2 and later with KAME IPsec. linux means Linux-2.5
+# and later with native IPSec support.
+#OS= openbsd
+#OS= netbsd
+#OS= freebsd
+#OS= freeswan
+#OS= darwin
+OS= linux
+
+.CURDIR:= $(shell pwd)
+VPATH= ${.CURDIR}/sysdep/${OS}
+
+PROG= isakmpd
+
+ifndef BINDIR
+BINDIR= /sbin
+endif
+
+#ifndef LDSTATIC
+#LDSTATIC= -static
+#endif
+
+SRCS= app.c attribute.c cert.c connection.c \
+ constants.c conf.c cookie.c crypto.c dh.c doi.c exchange.c \
+ exchange_num.c field.c gmp_util.c hash.c if.c ike_auth.c \
+ ike_main_mode.c ike_phase_1.c ike_quick_mode.c init.c \
+ ipsec.c ipsec_fld.c ipsec_num.c isakmpd.c isakmp_doi.c \
+ isakmp_fld.c isakmp_num.c key.c libcrypto.c log.c message.c \
+ math_2n.c math_group.c prf.c sa.c sysdep.c timer.c \
+ transport.c udp.c ui.c util.c virtual.c
+
+GENERATED= exchange_num.h ipsec_fld.h ipsec_num.h isakmp_fld.h \
+ isakmp_num.h
+CLEANFILES= exchange_num.c exchange_num.h ipsec_num.c ipsec_num.h \
+ isakmp_num.c isakmp_num.h ipsec_fld.c ipsec_fld.h \
+ isakmp_fld.c isakmp_fld.h
+MAN= isakmpd.8 isakmpd.conf.5 isakmpd.policy.5
+
+CFLAGS+= -O2 ${DEBUG} -Wall -DNEED_SYSDEP_APP \
+ -I${.CURDIR} -I${.CURDIR}/sysdep/${OS} -I. \
+
+# Different debugging & profiling suggestions
+
+# Include symbolic debugging info
+DEBUG= -g
+
+# Do execution time profiles
+#CFLAGS+= -pg
+
+# If you have ElectricFence available, you can spot abuses of the heap.
+# (/usr/ports/devel/ElectricFence)
+#LDADD+= -L/usr/local/lib -lefence
+#DPADD+= /usr/local/lib/libefence.a
+
+# If you like to use Boehm's garbage collector (/usr/ports/devel/boehm-gc).
+#LDADD+= -L/usr/local/lib -lgc
+#DPADD+= /usr/local/lib/libgc.a
+
+# You can also use Boehm's garbage collector as a means to find leaks.
+# XXX The defines below are GCC-specific. I think it is OK to require
+# XXX GCC if you are debugging isakmpd in this way.
+#LDADD+= -L/usr/local/lib -lleak
+#DPADD+= /usr/local/lib/libleak.a
+#CFLAGS+= -D'malloc(x)=({ \
+# void *GC_debug_malloc (size_t, char *, int); \
+# GC_debug_malloc ((x), __FILE__, __LINE__); \
+# })' \
+# -D'realloc(x,y)=({ \
+# void *GC_debug_realloc (void *, size_t, char *, int); \
+# GC_debug_realloc ((x), (y), __FILE__, __LINE__); \
+# })' \
+# -D'free(x)=({ \
+# void GC_debug_free (void *); \
+# GC_debug_free (x); \
+# })' \
+# -D'calloc(x,y)=malloc((x) * (y))' \
+# -D'strdup(x)=({ \
+# char *strcpy (char *, const char *); \
+# const char *_x_ = (x); \
+# char *_y_ = malloc (strlen (_x_) + 1); \
+# strcpy (_y_, _x_); \
+# })'
+
+# Ignore any files with these names...
+.PHONY: mksubdirs all clean cleandir cleandepend beforedepend \
+ afterdepend realclean realcleandepend
+
+# Default target, it needs to be the first target in makefile... :(
+
+all: ${PROG} mksubdirs
+
+ifneq ($(findstring install,$(MAKECMDGOALS)),install)
+# Skip 'regress' until the regress/ structure has gmake makefiles for it.
+#SUBDIR:= regress
+SUBDIR:= apps/certpatch
+mksubdirs:
+ $(foreach DIR, ${SUBDIR}, \
+ cd ${.CURDIR}/${DIR}; ${MAKE} ${MAKECMDGOALS};)
+
+# $(foreach DIR, ${SUBDIR}, \
+# cd ${DIR}; ${MAKE} CFLAGS="${CFLAGS}" \
+# MKDEP="${MKDEP}" ${MAKECMDGOALS})
+else
+mksubdirs:
+endif
+
+# DEPSRCS handling is *ugly*, I know...
+# What is does; keep orig SRCS in ORIGSRCS; potentially add stuff to
+# SRCS (include); let DEPSRCS be ORIGSRCS (sysdep.c -> sysdep/<os>/sysdep.c)
+# _plus_ any new sources, located either in cwd or sysdep/<os>. Phew.
+
+ORIGSRCS:= ${SRCS}
+-include sysdep/${OS}/GNUmakefile.sysdep
+
+FEATURES_UC= $(shell echo ${FEATURES} | tr '[:lower:]' '[:upper:]')
+CFLAGS+= $(foreach F, ${FEATURES_UC}, -DUSE_${F})
+-include $(foreach F, ${FEATURES}, features/${F})
+
+ifdef USE_KEYNOTE
+USE_LIBCRYPTO= yes
+LDADD+= -lkeynote -lm
+DPADD+= ${LIBKEYNOTE} ${LIBM}
+POLICY= policy.c
+CFLAGS+= -DUSE_KEYNOTE
+endif
+
+ifdef USE_LIBCRYPTO
+X509= x509.c
+CFLAGS+= -DUSE_LIBCRYPTO
+LDADD+= -lcrypto
+DPADD+= ${LIBCRYPTO}
+endif
+
+ifdef USE_RAWKEY
+USE_LIBCRYPTO= yes
+CFLAGS+= -DUSE_RAWKEY
+endif
+
+SRCS+= ${IPSEC_SRCS} ${X509} ${POLICY} ${EC} ${AGGRESSIVE} ${DNSSEC} \
+ $(ISAKMP_CFG) ${DPD} ${NAT_TRAVERSAL}
+CFLAGS+= ${IPSEC_CFLAGS}
+LDADD+= ${DESLIB}
+DPADD+= ${DESLIBDEP}
+
+DEPSRCS:= $(subst sysdep.c,${VPATH}/sysdep.c,${ORIGSRCS}) \
+ $(foreach FILE, $(filter-out ${ORIGSRCS},${SRCS}), \
+ $(wildcard ./${FILE} ${VPATH}/${FILE}))
+OBJS:= $(SRCS:%.c=%.o)
+
+# Generated targets
+exchange_num.c exchange_num.h: genconstants.sh exchange_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/exchange_num
+
+ipsec_fld.c ipsec_fld.h: genfields.sh ipsec_fld.fld
+ /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/ipsec_fld
+
+ipsec_num.c ipsec_num.h: genconstants.sh ipsec_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/ipsec_num
+
+isakmp_fld.c isakmp_fld.h: genfields.sh isakmp_fld.fld
+ /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/isakmp_fld
+
+isakmp_num.c isakmp_num.h: genconstants.sh isakmp_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/isakmp_num
+
+# Program rules
+${PROG} beforedepend: ${GENERATED}
+
+${PROG}: ${OBJS} ${DPADD}
+ ${CC} ${DEBUG} ${LDFLAGS} ${LDSTATIC} -o $@ ${OBJS} ${LDADD}
+
+# Depend rules
+depend: beforedepend .depend mksubdirs afterdepend
+ @true
+
+# Since 'mkdep' et al maybe doesn't exist...
+MKDEP:= ${CC} -MM
+
+.depend: ${SRCS}
+ @rm -f .depend
+ ${MKDEP} ${CFLAGS} ${DEPSRCS} > .depend
+
+afterdepend:
+
+ifneq ($(findstring clean, $(MAKECMDGOALS)), clean)
+# This will initially fail (when .depend does not exist), continue
+# to create .depend, then make will automatically restart to include
+# the generated .depend correctly. The '-' inhibits the warning msg.
+-include .depend
+endif
+
+# Clean rules
+
+cleandir: realclean realcleandepend mksubdirs
+
+clean: realclean mksubdirs
+
+cleandepend: realcleandepend mksubdirs
+
+realclean:
+ rm -f a.out core *.core ${PROG} ${OBJS} ${CLEANFILES}
+
+realcleandepend:
+ rm -f .depend tags
diff --git a/keyexchange/isakmpd-20041012/Makefile b/keyexchange/isakmpd-20041012/Makefile
new file mode 100644
index 0000000..2c04d8b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/Makefile
@@ -0,0 +1,187 @@
+# $OpenBSD: Makefile,v 1.57 2004/08/23 11:16:49 ho Exp $
+# $EOM: Makefile,v 1.78 2000/10/15 21:33:42 niklas Exp $
+
+#
+# Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+# Copyright (c) 2000, 2001 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+#
+# This makefile is a "pmake" one, i.e. the make variant commonly found in
+# BSD derived systems, where it is indeed named "make". Other systems
+# may provide this make variant as "pmake" or maybe "bsdmake".
+#
+
+# openbsd means OpenBSD 2.5 or newer. freeswan is the name for Linux with
+# FreeS/WAN integrated, freebsd/netbsd means FreeBSD/NetBSD with KAME IPsec.
+OS= openbsd
+#OS= netbsd
+#OS= freebsd
+#OS= freeswan
+#OS= bsdi
+
+# Compile-time configuration of otherwise optional features
+#FEATURES= tripledes des blowfish cast aes
+#FEATURES+= policy x509 ec aggressive debug gmp
+#FEATURES+= rawkey isakmp_cfg dnssec privsep nat_traversal dpd
+FEATURES= tripledes des blowfish cast aes
+FEATURES+= policy x509 ec aggressive debug
+FEATURES+= rawkey isakmp_cfg privsep nat_traversal dpd
+
+.PATH: ${.CURDIR}/sysdep/${OS}
+
+PROG= isakmpd
+BINDIR?= /sbin
+LDSTATIC?= -static
+SRCS= app.c attribute.c cert.c connection.c constants.c conf.c \
+ cookie.c crypto.c dh.c doi.c exchange.c exchange_num.c \
+ field.c gmp_util.c hash.c if.c ike_auth.c ike_main_mode.c \
+ ike_phase_1.c ike_quick_mode.c init.c ipsec.c ipsec_fld.c \
+ ipsec_num.c isakmpd.c isakmp_doi.c isakmp_fld.c isakmp_num.c \
+ key.c libcrypto.c log.c message.c math_2n.c math_group.c \
+ prf.c sa.c sysdep.c timer.c transport.c virtual.c udp.c \
+ ui.c util.c
+
+GENERATED= exchange_num.h ipsec_fld.h ipsec_num.h isakmp_fld.h \
+ isakmp_num.h
+CLEANFILES= exchange_num.c exchange_num.h ipsec_num.c ipsec_num.h \
+ isakmp_num.c isakmp_num.h ipsec_fld.c ipsec_fld.h \
+ isakmp_fld.c isakmp_fld.h
+MAN= isakmpd.8 isakmpd.conf.5 isakmpd.policy.5
+CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes \
+ -Wmissing-declarations -DNEED_SYSDEP_APP \
+ -I${.CURDIR} -I${.CURDIR}/sysdep/${OS} -I.
+#CFLAGS+= -Wsign-compare -Werror
+
+# Different debugging & profiling suggestions
+
+# Include symbolic debugging info
+#DEBUG= -g # OpenBSD
+#DEBUG_FLAGS= -g # FreeBSD
+#CFLAGS+= -g # NetBSD and others
+#STRIPFLAG= # NETBSD
+
+# Do execution time profiles
+#CFLAGS+= -pg
+
+# If you have ElectricFence available, you can spot abuses of the heap.
+# (/usr/ports/devel/ElectricFence)
+#LDADD+= -L/usr/local/lib -lefence
+#DPADD+= /usr/local/lib/libefence.a
+
+# If you like to use Boehm's garbage collector (/usr/ports/devel/boehm-gc).
+#LDADD+= -L/usr/local/lib -lgc
+#DPADD+= /usr/local/lib/libgc.a
+#CFLAGS+= -DUSE_BOEHM_GC -DGC_DEBUG
+# You can also use Boehm's garbage collector as a means to find leaks.
+# # setenv GC_FIND_LEAK
+
+SUBDIR= apps
+
+.include "sysdep/${OS}/Makefile.sysdep"
+
+.if ${FEATURES} != ""
+FEATURES_UC!= echo ${FEATURES} | tr '[:lower:]' '[:upper:]'
+CFLAGS+= ${FEATURES_UC:S/^/-DUSE_/g}
+.endif
+
+.if make(install)
+SUBDIR+= samples
+.endif
+
+.if !make(install) && !defined(NO_REGRESS)
+SUBDIR+= regress
+.endif
+
+.for FEATURE in ${FEATURES}
+.if exists(features/${FEATURE})
+.include "features/${FEATURE}"
+.endif
+.endfor
+
+.if ${FEATURES:Mgmp} == "gmp"
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+.else
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
+.endif
+
+.ifdef USE_KEYNOTE
+USE_LIBCRYPTO= yes
+USE_LIBDES= yes
+LDADD+= -lkeynote -lm
+DPADD+= ${LIBKEYNOTE} ${LIBM}
+CFLAGS+= -DUSE_KEYNOTE
+.endif
+
+.ifdef USE_RAWKEY
+USE_LIBCRYPTO= yes
+CFLAGS+= -DUSE_RAWKEY
+.endif
+
+.ifdef USE_LIBCRYPTO
+CFLAGS+= -DUSE_LIBCRYPTO
+LDADD+= -lcrypto
+DPADD+= ${LIBCRYPTO}
+.endif
+
+.ifdef USE_LIBDES
+CFLAGS+= -DUSE_LIBDES
+LDADD+= -ldes
+DPADD+= ${LIBDES}
+.endif
+
+SRCS+= ${IPSEC_SRCS} ${X509} ${POLICY} ${EC} ${AGGRESSIVE} ${DNSSEC} \
+ ${ISAKMP_CFG} ${PRIVSEP} ${DPD} ${NAT_TRAVERSAL}
+CFLAGS+= ${IPSEC_CFLAGS} ${DNSSEC_CFLAGS}
+
+LDADD+= ${DESLIB} ${LWRESLIB}
+DPADD+= ${DESLIBDEP} ${LWRESLIB}
+
+exchange_num.c exchange_num.h: genconstants.sh exchange_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/exchange_num
+
+ipsec_fld.c ipsec_fld.h: genfields.sh ipsec_fld.fld
+ /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/ipsec_fld
+
+ipsec_num.c ipsec_num.h: genconstants.sh ipsec_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/ipsec_num
+
+isakmp_fld.c isakmp_fld.h: genfields.sh isakmp_fld.fld
+ /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/isakmp_fld
+
+isakmp_num.c isakmp_num.h: genconstants.sh isakmp_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/isakmp_num
+
+${PROG} beforedepend: ${GENERATED}
+
+.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
+
+debug:
+ (cd ${.CURDIR}; ${MAKE} DEBUG="-g -Werror")
diff --git a/keyexchange/isakmpd-20041012/QUESTIONS b/keyexchange/isakmpd-20041012/QUESTIONS
new file mode 100644
index 0000000..91225cc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/QUESTIONS
@@ -0,0 +1,34 @@
+$OpenBSD: QUESTIONS,v 1.5 2003/11/05 12:31:21 jmc Exp $
+$EOM: QUESTIONS,v 1.12 1998/10/11 17:11:06 niklas Exp $
+
+Does the spec limit the count of SA payloads in a message? Where if so?
+[ Only the specific IKE main mode does. In the IKE spec.]
+
+The message ID field of the header, can it be considered a SA identifier
+if used together with the cookiepair? [Yes, it is meant to be that]
+
+DOI 0, what protocols are defined for it? Where?
+
+Isn't this a potential DOS attack:
+Hostile user listens for ISAKMP traffic, and then extracts cookiepairs
+and message IDs which he uses to flood any of the peers with spoofed
+packets pretending to be the other one. Most probably these packets will
+result in error notifications which potentially result in SA tear-down?
+Maybe should notifications never be issued for erroneous packets which
+cannot be authenticated? Or should we not tear down SAs as results of
+notifications?
+
+Certicom claims to hold licenses for Elliptic Curve Cryptography? Does this
+concern us? See: http://grouper.ieee.org/groups/1363/P1363/patents.html
+
+Main mode when using public key encryption authentication does not look
+like an identity protection exchange to me. Must I really get rid of
+the generic ISAKMP payload presense tests?
+
+IV generation is not described precisely in Appendix B of -oakley-08.txt:
+'Subsequent messages MUST use the last CBC encryption block from the previous
+message as their IV'. This probably means that we take the new IV from the
+last encrypted block of the last message we sent. The SSH testing site uses
+the last block from the last message they received. This is probably not
+what was meant and should be clarified on ipsec@tis.com.
+[ From what we have gathered this is what is meant. ]
diff --git a/keyexchange/isakmpd-20041012/README b/keyexchange/isakmpd-20041012/README
new file mode 100644
index 0000000..13df6a1
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/README
@@ -0,0 +1,68 @@
+$OpenBSD: README,v 1.19 2003/02/22 06:57:07 kjell Exp $
+$EOM: README,v 1.28 1999/10/10 22:53:24 angelos Exp $
+
+This is isakmpd, a BSD-licensed ISAKMP/Oakley (a.k.a. IKE)
+implementation. It's written by Niklas Hallqvist and Niels Provos,
+funded by Ericsson Radio Systems AB. Isakmpd's home is in the
+OpenBSD main source tree under src/sbin/isakmpd. Look at
+http://www.openbsd.org/ for details on how to get OpenBSD source.
+
+Isakmpd is being developed under OpenBSD, with OpenBSD as its primary
+target, however, it is ported to Linux with FreeS/WAN IPsec. The
+makefile support assumes a BSD environment nonetheless as it is not too
+hard to get such an environment to work under other operating systems.
+For example, Red Hat 5.2 shipped with pmake installed. Read sysdep/README
+for further details about this issue. Other systems isakmpd has been
+ported to, but no code has been made available for, includes Solaris
+and Win32s. I mention this just because it shows that the code is
+fairly portable.
+
+First edit the Makefile in a manner you see fit. Specifically the OS
+define is important to get right of course.
+Assuming you have an OpenBSD /usr/share/mk and use the OpenBSD (or
+similar) make(1), you build isakmpd this way:
+
+make obj && make depend && make
+
+Then obj/isakmpd will be the daemon. I suggest you try it by running
+under gdb with args similar to:
+ -d -n -p5000 -DA=99 -f/tmp/isakmpd.fifo -csamples/VPN-east.conf
+
+That will run isakmpd in the foreground, not connected to any application
+(like an IPsec implementation) logging to stderr with full debugging output,
+listening on UDP port 5000, accepting control commands via the named pipe
+called /tmp/isakmpd.fifo and reading its configuration from the
+VPN-east.conf file (found in the isakmpd/samples directory).
+
+If you are root you can try to run without -n -p5000 thus getting it to
+talk to your IPsec stack and use the standard port 500 instead.
+
+The logging classes are Miscellaneous = 0, Transports = 1, Messages = 2,
+Crypto = 3, Timers = 4, System Dependencies = 5, Security Associations = 6,
+and Exchanges = 7. The debug levels increase in verbosity from 0 (off) to
+99 (max). Read log.[ch] and ui.c to see how to alter the debugging levels.
+
+Now you have setup your daemon and can watch incoming negotiations.
+But how do you get such? Either use http://isakmp-test.ssh.fi/,
+there's an excellent service, just waiting for you. Or you can try to
+start another isakmpd on another port (say -p5001 or so, instead)
+and another fifo (let's say /tmp/other.fifo). Then edit the config
+file to have some peer descriptions that fit your need and issue a
+command like this:
+
+$ echo "c IPsec-east-west" >/tmp/other.fifo
+
+and watch. You can turn on debugging on that isakmpd too of course, for
+greater fun. This rudimentary user interface is slightly described in
+DESIGN-NOTES. If you are going to look at the config file, don't be scared,
+the man page isakmpd.conf(5) covers every detail, and the flexibility will
+be hidden under a userfriendlier layer in a later release. I did this
+first config-file syntax just because it should be easy to parse. The man
+page isakmpd.policy(5) describes the policy model used in conjunction with
+KeyNote.
+
+Happy IKEing!
+
+Niklas Hallqvist <niklas@openbsd.org>
+Niels Provos <provos@openbsd.org>
+Håkan Olsson <ho@openbsd.org>
diff --git a/keyexchange/isakmpd-20041012/README.PKI b/keyexchange/isakmpd-20041012/README.PKI
new file mode 100644
index 0000000..4b7d9f1
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/README.PKI
@@ -0,0 +1,60 @@
+$OpenBSD: README.PKI,v 1.7 1999/10/01 14:10:45 niklas Exp $
+$EOM: README.PKI,v 1.7 1999/09/30 13:40:38 niklas Exp $
+
+1 Make sure you have an RSA-enabled isakmpd. An easy way to do this
+ is to install a dynamically linkable version of libcrypto from
+ OpenSSL and install it where the run-time linker can find it.
+
+2 Create your own CA as root.
+
+ openssl genrsa -out /etc/ssl/private/ca.key 1024
+ openssl req -new -key /etc/ssl/private/ca.key \
+ -out /etc/ssl/private/ca.csr
+
+ You are now being asked to enter information that will be incorporated
+ into your certificate request. What you are about to enter is what is
+ called a Distinguished Name or a DN. There are quite a few fields but
+ you can leave some blank. For some fields there will be a default
+ value, if you enter '.', the field will be left blank.
+
+ openssl x509 -req -days 365 -in /etc/ssl/private/ca.csr \
+ -signkey /etc/ssl/private/ca.key \
+ -out /etc/ssl/ca.crt
+
+3 Create keys and certificates for your isakmpd peers. This step as well
+ as the next one, needs to be done for every peer. Furthermore the
+ last step will need to be done once for each ID you want the peer
+ to have. The 10.0.0.1 below symbolizes that ID, and should be
+ changed for each invocation. You will be asked for a DN for each
+ run too. See to encode the ID in the common name too, so it gets
+ unique.
+
+ openssl genrsa -out /etc/isakmpd/private/local.key 1024
+ openssl req -new -key /etc/isakmpd/private/local.key \
+ -out /etc/isakmpd/private/10.0.0.1.csr
+
+ Now take these certificate signing requests to your CA and process
+ them like below. You have to add some extensions to the certificate
+ in order to make it usable for isakmpd, which is why you will need
+ to run certpatch. Replace 10.0.0.1 with the IP-address which isakmpd
+ will be using for identity.
+
+ openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \
+ -CAkey /etc/ssl/private/ca.key -CAcreateserial \
+ -out 10.0.0.1.crt
+ certpatch -i 10.0.0.1 -k /etc/ssl/private/ca.key \
+ 10.0.0.1.crt 10.0.0.1.crt
+
+ Put the certificate (the file ending in .crt) in /etc/isakmpd/certs/
+ on your local system. Also carry over the CA cert /etc/ssl/ca.crt
+ and put it in /etc/isakmpd/ca/.
+
+4 See to that your config files will point out the directories where
+ you keep certificates. I.e. add something like this to
+ /etc/isakmpd/isakmpd.conf:
+
+ # Certificates stored in PEM format
+ [X509-certificates]
+ CA-directory= /etc/isakmpd/ca/
+ Cert-directory= /etc/isakmpd/certs/
+ Private-key= /etc/isakmpd/private/local.key
diff --git a/keyexchange/isakmpd-20041012/TO-DO b/keyexchange/isakmpd-20041012/TO-DO
new file mode 100644
index 0000000..7e397e4
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/TO-DO
@@ -0,0 +1,145 @@
+$OpenBSD: TO-DO,v 1.26 2003/08/28 14:43:35 markus Exp $
+$EOM: TO-DO,v 1.45 2000/04/07 22:47:38 niklas Exp $
+
+This file mixes small nitpicks with large projects to be done.
+
+* Add debugging messages, maybe possible to control asynchronously. [done]
+
+* Implement the local policy governing logging and notification of exceptional
+ conditions.
+
+* A field description mechanism used for things like making packet dumps
+ readable etc. Both Photurisd and Pluto does this. [done]
+
+* Fix the cookies. <Niels> [done]
+
+* Garbage collect transports (ref-counting?). [done]
+
+* Retransmission/dup packet handling. [done]
+
+* Generic payload checks. [mostly done]
+
+* For math, speed up multiplication and division functions.
+
+* Cleanup of SAs when dropping messages. [done]
+
+* Look over message resource tracking. [done]
+
+* Retransmission timing & count adaptivity and configurability.
+ [configurability done]
+
+* Quick mode exchanges [done]
+
+* Aggressive mode exchange. [done]
+
+* Finish main mode exchange [done]
+
+* Separation of key exchange from the IPsec DOI, i.e. factor out IKE details.
+
+* Setup the IPsec situation field in the main mode. [done]
+
+* Kernel interface for IPsec parameter passing. [done]
+
+* Notify of unsupported situations.
+
+* Set/get field macros generated from the field descriptions. [done]
+
+* SIGHUP handler with reparsing of config file. [done]
+
+* RSA signature authentication. <Niels> [done]
+
+* DSS signature authentication.
+
+* RSA encryption authentication.
+
+* New group mode.
+
+* DELETE payload handling, and generation from ui. [generation done]
+
+* Deal well with incoming informational exchanges. [done]
+
+* Generate all possible SA attributes in quick mode. [done]
+
+* Validate incoming attribute according to policy, main mode. [done]
+
+* Validate incoming attribute according to policy, quick mode. [done]
+
+* Cleanup reserved SPIs on cleanup of associated SAs. [done]
+
+* Validate attribute types (i.e. that what the specs tells should be
+ basic).
+
+* Cleanup reserved SPIs in proposals never chosen. [done]
+
+* Add time measuring and reporting to the exchange code for catching of
+ bottlenecks.
+
+* Rescan interfaces on SIGHUP and on reception of messages on the INADDR_ANY
+ listener socket. [done]
+
+* Validate the configuration file.
+
+* Do a soft-limit on ISAKMP SA lifetime. [done]
+
+* Let the hard-limit on ISAKMP SA lifetime destroy the SA ASAP. [done]
+
+* IPsec rekeying. [done]
+
+* Store tunnels into SPD, and handle acquire SA events. [done]
+
+* If an exchange is on-going when a rekey event happens, drop the request.
+ [done]
+
+* INITIAL CONTACT notification sending when appropriate. [done]
+
+* INITIAL CONTACT notification handling. [done]
+
+* IPsec SAs could also do with timers protecting its lifetime, if say,
+ someone changed the lifetime of the IPsec SA in stack under us. [done]
+
+* Handle notifications showing the peer did not want to continue this exchange.
+
+* Flexible identification.
+
+* Remove referring flows when a SPI is removed. [done]
+
+* IPCOMP.
+
+* Acknowledged notification exchange.
+
+* Tiger hash.
+
+* El-Gamal public key encryption.
+
+* Check of attributes not being changed by the responder in phase 2.
+
+* See to the commit bit will never be used in phase 1. Give INVALID-FLAGS
+ if seeing it.
+
+* Base mode.
+
+* IKECFG [protocol done, configuration controls remain]
+
+* XAUTH framework.
+
+* PKCS#11
+
+* XAUTH hybrid frame work.
+
+* Specify extra certificates to send somehow.
+
+* Handle CERTs anywhere in an exchange.
+
+* Add a way to do multiple configuration commands via ui.
+
+* Replace ui's fifo with a slightly more versatile interface.
+
+* Report current configuration. [done]
+
+* IPv6 [done]
+
+* AES in phase 1 [done]
+
+* x509_certreq_validate needs implementing.
+
+* Smartcard support.
diff --git a/keyexchange/isakmpd-20041012/app.c b/keyexchange/isakmpd-20041012/app.c
new file mode 100644
index 0000000..a04aa14
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/app.c
@@ -0,0 +1,63 @@
+/* $OpenBSD: app.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: app.c,v 1.6 1999/05/01 20:21:06 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * XXX This is just a wrapper module for now. Later we might handle many
+ * applications simultaneously but right now, we assume one system-dependent
+ * one only.
+ */
+
+#include "sysdep.h"
+
+#include "app.h"
+#include "log.h"
+
+int app_socket;
+
+/* Set this to not get any applications setup. */
+int app_none = 0;
+
+/* Initialize applications. */
+void
+app_init(void)
+{
+ if (app_none)
+ return;
+ app_socket = sysdep_app_open();
+ if (app_socket == -1)
+ log_fatal("app_init: cannot open connection to application");
+}
+
+void
+app_handler(void)
+{
+ sysdep_app_handler(app_socket);
+}
diff --git a/keyexchange/isakmpd-20041012/app.h b/keyexchange/isakmpd-20041012/app.h
new file mode 100644
index 0000000..96a2864
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/app.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: app.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: app.h,v 1.4 1999/04/02 00:58:16 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _APP_H_
+#define _APP_H_
+
+extern int app_socket;
+extern int app_none;
+
+extern void app_conf_init_hook(void);
+extern void app_handler(void);
+extern void app_init(void);
+
+#endif /* _APP_H_ */
diff --git a/keyexchange/isakmpd-20041012/apps/Makefile b/keyexchange/isakmpd-20041012/apps/Makefile
new file mode 100644
index 0000000..7d1bbe9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/apps/Makefile
@@ -0,0 +1,34 @@
+# $OpenBSD: Makefile,v 1.2 2003/06/03 14:35:00 ho Exp $
+# $EOM: Makefile,v 1.2 1999/07/17 20:44:12 niklas Exp $
+
+#
+# Copyright (c) 1999 Niels Provos. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+SUBDIR= certpatch
+
+#.include <bsd.subdir.mk>
diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/.cvsignore b/keyexchange/isakmpd-20041012/apps/certpatch/.cvsignore
new file mode 100644
index 0000000..6203864
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/apps/certpatch/.cvsignore
@@ -0,0 +1,3 @@
+certpatch
+certpatch.cat8
+obj
diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/GNUmakefile b/keyexchange/isakmpd-20041012/apps/certpatch/GNUmakefile
new file mode 100644
index 0000000..3cd8e3a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/apps/certpatch/GNUmakefile
@@ -0,0 +1,55 @@
+# $OpenBSD: Makefile,v 1.7 2003/06/03 14:35:00 ho Exp $
+# $EOM: Makefile,v 1.6 2000/03/28 21:22:06 ho Exp $
+
+#
+# Copyright (c) 1999 Niels Provos. All rights reserved.
+# Copyright (c) 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+PROG= certpatch
+SRCS= certpatch.c
+BINDIR?= /usr/sbin
+TOPSRC= ${.CURDIR}../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS= linux
+FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//'
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+LDFLAGS+= -lcrypto -lssl -lgmp
+MAN= certpatch.8
+
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+
+# Override LIBSYSDEPDIR definition from Makefile.sysdep
+LIBSYSDEPDIR= ${TOPSRC}/sysdep/common/libsysdep
+
+all: ${PROG}
+
+clean:
+ rm -f ${PROG}
diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/Makefile b/keyexchange/isakmpd-20041012/apps/certpatch/Makefile
new file mode 100644
index 0000000..c422938
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/apps/certpatch/Makefile
@@ -0,0 +1,58 @@
+# $OpenBSD: Makefile,v 1.7 2003/06/03 14:35:00 ho Exp $
+# $EOM: Makefile,v 1.6 2000/03/28 21:22:06 ho Exp $
+
+#
+# Copyright (c) 1999 Niels Provos. All rights reserved.
+# Copyright (c) 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+PROG= certpatch
+SRCS= certpatch.c
+BINDIR?= /usr/sbin
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//'
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+LDADD+= -lcrypto
+DPADD+= ${LIBCRYPTO}
+MAN= certpatch.8
+
+.if ${FEATURES:Mgmp} == "gmp"
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+.else
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
+.endif
+
+.include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep"
+# Override LIBSYSDEPDIR definition from Makefile.sysdep
+LIBSYSDEPDIR= ${TOPSRC}/sysdep/common/libsysdep
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.8 b/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.8
new file mode 100644
index 0000000..1c1b629
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.8
@@ -0,0 +1,85 @@
+.\" $OpenBSD: certpatch.8,v 1.8 2003/06/04 07:31:17 ho Exp $
+.\" $EOM: certpatch.8,v 1.5 2000/04/07 22:17:11 niklas Exp $
+.\"
+.\" Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
+.\" Copyright (c) 1999 Angelos D. Keromytis. 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+.\"
+.\" Manual page, using -mandoc macros
+.\"
+.Dd July 18, 1999
+.Dt CERTPATCH 8
+.Os
+.Sh NAME
+.Nm certpatch
+.Nd add subjectAltName identities to X.509 certificates
+.Sh SYNOPSIS
+.Nm certpatch
+.Op Fl t Ar identity-type
+.Fl i
+.Ar identity
+.Fl k
+.Ar signing-key
+.Ar input-certificate output-certificate
+.Sh DESCRIPTION
+.Nm
+alters PEM-encoded X.509 certificates by adding a subjectAltName extension
+containing an identity used by the signature-based authentication schemes
+of the ISAKMP protocol.
+After the addition the certificate will be signed
+once again with the supplied CA signing key.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl t Ar identity-type
+If given, the
+.Fl t
+option specifies the type of the given identity.
+Currently
+.Li ip ,
+.Li fqdn ,
+and
+.Li ufqdn
+are recognized.
+The default is
+.Li ip .
+.It Fl i Ar identity
+The
+.Fl i
+option takes an argument which is the identity to put into the
+subjectAltName field of the certificate.
+If the identity-type is
+.Li ip ,
+this argument should be an IPv4 address in dotted decimal notation.
+.It Fl k Ar signing-key
+The
+.Fl k
+option specifies the key used for signing the certificate once the
+subjectAltName extension has been added.
+The key is specified by
+the filename where it is stored in PEM format.
+.El
+.Sh SEE ALSO
+.Xr isakmpd 8 ,
+.Xr ssl 8
diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.c b/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.c
new file mode 100644
index 0000000..0a0125a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.c
@@ -0,0 +1,317 @@
+/* $OpenBSD: certpatch.c,v 1.21 2003/06/04 07:31:17 ho Exp $ */
+/* $EOM: certpatch.c,v 1.11 2000/12/21 14:50:09 ho Exp $ */
+
+/*
+ * Copyright (c) 1999 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * This program takes a certificate generated by ssleay and a
+ * private key. It encodes a new id as subject alt name
+ * extension into the certifcate. The result gets written as
+ * new certificate that can be used by isakmpd.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "sysdep.h"
+
+#ifdef KAME
+# ifdef CRYPTO
+# include <openssl/rsa.h>
+# endif
+#else
+# include <openssl/rsa.h>
+#endif
+
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+
+#include "conf.h"
+#include "ipsec_num.h"
+#include "log.h"
+#include "math_mp.h"
+#include "x509.h"
+
+#define IDTYPE_IP "ip"
+#define IDTYPE_FQDN "fqdn"
+#define IDTYPE_UFQDN "ufqdn"
+
+int
+main (int argc, char **argv)
+{
+ char *usage = "%s [-t idtype] -i id -k keyfile certin certout\n\n"
+ "This programs takes a certificate and adds a subjectAltName extension\n"
+ "with the identication given as command line argument. Be sure that \n"
+ "the signing key matches the issuer.\n";
+ EVP_PKEY *pkey_priv;
+ X509 *cert;
+ BIO *file;
+ const EVP_MD *digest;
+ X509_EXTENSION *ex = NULL;
+ ASN1_OCTET_STRING *data = NULL;
+ struct in_addr saddr;
+ unsigned char ipaddr[6], *new_id;
+ char *type = IDTYPE_IP, *keyfile = NULL, *id = NULL;
+ char *certin, *certout;
+ int ch, err;
+
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ unsigned char *p;
+ ASN1_STRING str;
+ int i;
+#endif
+
+
+ /* read command line arguments */
+ while ((ch = getopt (argc, argv, "t:k:i:")) != -1)
+ switch (ch) {
+ case 't':
+ type = optarg;
+ break;
+ case 'k':
+ keyfile = optarg;
+ break;
+ case 'i':
+ id = optarg;
+ break;
+ default:
+ fprintf (stderr, usage, argv[0]);
+ return (1);
+ }
+
+ argc -= optind;
+
+ if (argc != 2) {
+ fprintf (stderr, usage, argv[0]);
+ return (1);
+ }
+
+ argv += optind;
+
+ certin = argv[0];
+ certout = argv[1];
+
+ /* Check ID */
+
+ if ((strcasecmp (IDTYPE_IP, type) != 0 &&
+ strcasecmp (IDTYPE_FQDN, type) != 0 &&
+ strcasecmp (IDTYPE_UFQDN, type) != 0) || id == NULL)
+ {
+ printf ("wrong id type or missing id\n");
+ return (1);
+ }
+
+ /*
+ * X509_verify will fail, as will all other functions that call
+ * EVP_get_digest_byname.
+ */
+
+ SSLeay_add_all_algorithms ();
+
+ /* Use a certificate created by ssleay and add the appr. extension */
+ printf ("Reading ssleay created certificate %s and modify it\n",
+ certin);
+ file = BIO_new (BIO_s_file ());
+ if (BIO_read_filename (file, certin) == -1)
+ {
+ perror ("read");
+ return (1);
+ }
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ cert = PEM_read_bio_X509 (file, NULL, NULL, NULL);
+#else
+ cert = PEM_read_bio_X509 (file, NULL, NULL);
+#endif
+ BIO_free (file);
+ if (cert == NULL)
+ {
+ printf ("PEM_read_bio_X509 () failed\n");
+ return (1);
+ }
+
+ /* Get the digest for the actual signing */
+ digest = EVP_get_digestbyname (OBJ_nid2sn (OBJ_obj2nid (cert->sig_alg->algorithm)));
+
+ if (!X509_set_version (cert, 2))
+ {
+ printf ("X509 failed to set version number\n");
+ return (1);
+ }
+
+ if (!strcasecmp (IDTYPE_IP, type))
+ {
+ if (inet_aton (id, &saddr) == 0)
+ {
+ printf ("inet_aton () failed\n");
+ return (1);
+ }
+
+ saddr.s_addr = htonl (saddr.s_addr);
+ ipaddr[0] = 0x87;
+ ipaddr[1] = 0x04;
+ ipaddr[2] = saddr.s_addr >> 24;
+ ipaddr[3] = (saddr.s_addr >> 16) & 0xff;
+ ipaddr[4] = (saddr.s_addr >> 8) & 0xff;
+ ipaddr[5] = saddr.s_addr & 0xff;
+
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ str.length = 6;
+ str.type = V_ASN1_OCTET_STRING;
+ str.data = ipaddr;
+ data = ASN1_OCTET_STRING_new ();
+ if (!data)
+ {
+ perror ("ASN1_OCTET_STRING_new() failed");
+ return (1);
+ }
+
+ i = i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, NULL);
+ if (!ASN1_STRING_set ((ASN1_STRING *)data,NULL,i))
+ {
+ perror ("ASN1_STRING_set() failed");
+ return (1);
+ }
+ p = (unsigned char *)data->data;
+ i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, &p);
+ data->length = i;
+#else
+ data = X509v3_pack_string (NULL, V_ASN1_OCTET_STRING, ipaddr, 6);
+#endif
+ }
+ else if (!strcasecmp (IDTYPE_FQDN, type) || !strcasecmp (IDTYPE_UFQDN, type))
+ {
+ new_id = malloc (strlen (id) + 2);
+ if (new_id == NULL)
+ {
+ printf ("malloc () failed\n");
+ return (1);
+ }
+
+ if (!strcasecmp (IDTYPE_FQDN, type))
+ new_id[0] = 0x82;
+ else
+ new_id[0] = 0x81; /* IDTYPE_UFQDN */
+
+ memcpy (new_id + 2, id, strlen(id));
+ new_id[1] = strlen (id);
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ str.length = strlen (id) + 2;
+ str.type = V_ASN1_OCTET_STRING;
+ str.data = new_id;
+ data = ASN1_OCTET_STRING_new ();
+ if (!data)
+ {
+ perror ("ASN1_OCTET_STRING_new() failed");
+ return (1);
+ }
+
+ i = i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, NULL);
+ if (!ASN1_STRING_set ((ASN1_STRING *)data,NULL,i))
+ {
+ perror ("ASN1_STRING_set() failed");
+ return (1);
+ }
+ p = (unsigned char *)data->data;
+ i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, &p);
+ data->length = i;
+#else
+ data = X509v3_pack_string (NULL, V_ASN1_OCTET_STRING, new_id,
+ strlen (id) + 2);
+#endif
+ free (new_id);
+ }
+
+ /* XXX This is a hack, how to do better? */
+ data->type = 0x30;
+ data->data[0] = 0x30;
+ ex = X509_EXTENSION_create_by_NID (NULL, NID_subject_alt_name, 1, data);
+
+ if (ex == NULL)
+ {
+ printf ("X509_EXTENSION_create ()\n");
+ return (1);
+ }
+
+ X509_add_ext (cert, ex, -1);
+
+ file = BIO_new (BIO_s_file ());
+ if (BIO_read_filename (file, keyfile) == -1)
+ {
+ perror ("open");
+ return (1);
+ }
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ if ((pkey_priv = PEM_read_bio_PrivateKey (file, NULL, NULL, NULL)) == NULL)
+#else
+ if ((pkey_priv = PEM_read_bio_PrivateKey (file, NULL, NULL)) == NULL)
+#endif
+ {
+ printf ("Can not read private key %s\n", keyfile);
+ return (1);
+ }
+ BIO_free (file);
+
+ printf ("Creating Signature: PKEY_TYPE = %s: ",
+ pkey_priv->type == EVP_PKEY_RSA ? "RSA" : "unknown");
+ err = X509_sign (cert, pkey_priv, digest);
+ printf ("X509_sign: %d ", err);
+ if (!err)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+ printf ("\n");
+
+ file = BIO_new (BIO_s_file ());
+ if (BIO_write_filename (file, certout) == -1)
+ {
+ perror ("open");
+ return (1);
+ }
+
+ printf ("Writing new certificate to %s\n", certout);
+ PEM_write_bio_X509 (file, cert);
+ BIO_free (file);
+
+ return (0);
+}
diff --git a/keyexchange/isakmpd-20041012/attribute.c b/keyexchange/isakmpd-20041012/attribute.c
new file mode 100644
index 0000000..362805b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/attribute.c
@@ -0,0 +1,112 @@
+/* $OpenBSD: attribute.c,v 1.11 2004/05/14 08:42:56 hshoexer Exp $ */
+/* $EOM: attribute.c,v 1.10 2000/02/20 19:58:36 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "conf.h"
+#include "log.h"
+#include "isakmp.h"
+#include "util.h"
+
+u_int8_t *
+attribute_set_basic(u_int8_t *buf, u_int16_t type, u_int16_t value)
+{
+ SET_ISAKMP_ATTR_TYPE(buf, ISAKMP_ATTR_MAKE(1, type));
+ SET_ISAKMP_ATTR_LENGTH_VALUE(buf, value);
+ return buf + ISAKMP_ATTR_VALUE_OFF;
+}
+
+u_int8_t *
+attribute_set_var(u_int8_t *buf, u_int16_t type, u_int8_t *value,
+ u_int16_t len)
+{
+ SET_ISAKMP_ATTR_TYPE(buf, ISAKMP_ATTR_MAKE(0, type));
+ SET_ISAKMP_ATTR_LENGTH_VALUE(buf, len);
+ memcpy(buf + ISAKMP_ATTR_VALUE_OFF, value, len);
+ return buf + ISAKMP_ATTR_VALUE_OFF + len;
+}
+
+/*
+ * Execute a function FUNC taking an attribute type, value, length and ARG
+ * as arguments for each attribute in the area of ISAKMP attributes located
+ * at BUF, sized SZ. If any invocation fails, the processing aborts with a
+ * -1 return value. If all goes well return zero.
+ */
+int
+attribute_map(u_int8_t *buf, size_t sz, int (*func)(u_int16_t, u_int8_t *,
+ u_int16_t, void *), void *arg)
+{
+ u_int8_t *attr;
+ int fmt;
+ u_int16_t type;
+ u_int8_t *value;
+ u_int16_t len;
+
+ for (attr = buf; attr < buf + sz; attr = value + len) {
+ if (attr + ISAKMP_ATTR_VALUE_OFF > buf + sz)
+ return -1;
+ type = GET_ISAKMP_ATTR_TYPE(attr);
+ fmt = ISAKMP_ATTR_FORMAT(type);
+ type = ISAKMP_ATTR_TYPE(type);
+ value = attr + (fmt ? ISAKMP_ATTR_LENGTH_VALUE_OFF
+ : ISAKMP_ATTR_VALUE_OFF);
+ len = (fmt ? ISAKMP_ATTR_LENGTH_VALUE_LEN
+ : GET_ISAKMP_ATTR_LENGTH_VALUE(attr));
+ if (value + len > buf + sz)
+ return -1;
+ if (func(type, value, len, arg))
+ return -1;
+ }
+ return 0;
+}
+
+int
+attribute_set_constant(char *section, char *tag, struct constant_map *map,
+ int attr_class, u_int8_t **attr)
+{
+ char *name;
+ int value;
+
+ name = conf_get_str(section, tag);
+ if (!name) {
+ LOG_DBG((LOG_MISC, 70,
+ "attribute_set_constant: no %s in the %s section", tag,
+ section));
+ return -1;
+ }
+ value = constant_value(map, name);
+ *attr = attribute_set_basic(*attr, attr_class, value);
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/attribute.h b/keyexchange/isakmpd-20041012/attribute.h
new file mode 100644
index 0000000..aa835cf
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/attribute.h
@@ -0,0 +1,47 @@
+/* $OpenBSD: attribute.h,v 1.6 2004/05/14 08:42:56 hshoexer Exp $ */
+/* $EOM: attribute.h,v 1.2 1998/09/29 21:51:07 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _ATTRIBUTE_H_
+#define _ATTRIBUTE_H_
+
+#include <sys/types.h>
+
+struct constant_map;
+
+extern int attribute_map(u_int8_t *, size_t, int (*)(u_int16_t,
+ u_int8_t *, u_int16_t, void *), void *);
+extern u_int8_t *attribute_set_basic(u_int8_t *, u_int16_t, u_int16_t);
+extern int attribute_set_constant(char *, char *, struct constant_map *,
+ int, u_int8_t **);
+extern u_int8_t *attribute_set_var(u_int8_t *, u_int16_t, u_int8_t *,
+ u_int16_t);
+
+#endif /* _ATTRIBUTE_H_ */
diff --git a/keyexchange/isakmpd-20041012/cert.c b/keyexchange/isakmpd-20041012/cert.c
new file mode 100644
index 0000000..d04b964
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/cert.c
@@ -0,0 +1,160 @@
+/* $OpenBSD: cert.c,v 1.28 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: cert.c,v 1.18 2000/09/28 12:53:27 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "isakmp_num.h"
+#include "log.h"
+#include "cert.h"
+
+#ifdef USE_X509
+#include "x509.h"
+#endif
+
+#ifdef USE_KEYNOTE
+#include "policy.h"
+#endif
+
+struct cert_handler cert_handler[] = {
+#ifdef USE_X509
+ {
+ ISAKMP_CERTENC_X509_SIG,
+ x509_cert_init, x509_crl_init, x509_cert_get, x509_cert_validate,
+ x509_cert_insert, x509_cert_free,
+ x509_certreq_validate, x509_certreq_decode, x509_free_aca,
+ x509_cert_obtain, x509_cert_get_key, x509_cert_get_subjects,
+ x509_cert_dup, x509_serialize, x509_printable, x509_from_printable
+ },
+#endif
+#ifdef USE_KEYNOTE
+ {
+ ISAKMP_CERTENC_KEYNOTE,
+ keynote_cert_init, NULL, keynote_cert_get, keynote_cert_validate,
+ keynote_cert_insert, keynote_cert_free,
+ keynote_certreq_validate, keynote_certreq_decode, keynote_free_aca,
+ keynote_cert_obtain, keynote_cert_get_key, keynote_cert_get_subjects,
+ keynote_cert_dup, keynote_serialize, keynote_printable,
+ keynote_from_printable
+ },
+#endif
+};
+
+/* Initialize all certificate handlers */
+int
+cert_init(void)
+{
+ size_t i;
+ int err = 1;
+
+ for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++)
+ if (cert_handler[i].cert_init &&
+ !(*cert_handler[i].cert_init)())
+ err = 0;
+
+ return err;
+}
+
+int
+crl_init(void)
+{
+ size_t i;
+ int err = 1;
+
+ for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++)
+ if (cert_handler[i].crl_init && !(*cert_handler[i].crl_init)())
+ err = 0;
+
+ return err;
+}
+
+struct cert_handler *
+cert_get(u_int16_t id)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++)
+ if (id == cert_handler[i].id)
+ return &cert_handler[i];
+ return 0;
+}
+
+/*
+ * Decode the certificate request of type TYPE contained in DATA extending
+ * DATALEN bytes. Return a certreq_aca structure which the caller is
+ * responsible for deallocating.
+ */
+struct certreq_aca *
+certreq_decode(u_int16_t type, u_int8_t *data, u_int32_t datalen)
+{
+ struct cert_handler *handler;
+ struct certreq_aca aca, *ret;
+
+ handler = cert_get(type);
+ if (!handler)
+ return 0;
+
+ aca.id = type;
+ aca.handler = handler;
+
+ if (datalen > 0) {
+ aca.data = handler->certreq_decode(data, datalen);
+ if (!aca.data)
+ return 0;
+ } else
+ aca.data = 0;
+
+ ret = malloc(sizeof aca);
+ if (!ret) {
+ log_error("certreq_decode: malloc (%lu) failed",
+ (unsigned long)sizeof aca);
+ handler->free_aca(aca.data);
+ return 0;
+ }
+ memcpy(ret, &aca, sizeof aca);
+ return ret;
+}
+
+void
+cert_free_subjects(int n, u_int8_t **id, u_int32_t *len)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ free(id[i]);
+ free(id);
+ free(len);
+}
diff --git a/keyexchange/isakmpd-20041012/cert.h b/keyexchange/isakmpd-20041012/cert.h
new file mode 100644
index 0000000..151b2f9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/cert.h
@@ -0,0 +1,96 @@
+/* $OpenBSD: cert.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */
+/* $EOM: cert.h,v 1.8 2000/09/28 12:53:27 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niels Provos. All rights reserved.
+ * Copyright (c) 2000, 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CERT_H_
+#define _CERT_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+/*
+ * CERT handler for each kind of certificate:
+ *
+ * cert_init - initialize CERT handler.
+ * crl_init - initialize CRLs, if applicable.
+ * cert_get - get a certificate in internal representation from raw data.
+ * cert_validate - validated a certificate, if it returns != 0 we can use it.
+ * cert_insert - inserts cert into memory storage, we can retrieve with
+ * cert_obtain.
+ * cert_dup - duplicate a certificate
+ * cert_serialize - convert to a "serialized" form; KeyNote stays the same,
+ * X509 is converted to the ASN1 notation.
+ * cert_printable - for X509, the hex representation of the serialized form;
+ * for KeyNote, itself.
+ * cert_from_printable - the reverse of cert_printable
+ */
+
+struct cert_handler {
+ u_int16_t id; /* ISAKMP Cert Encoding ID */
+ int (*cert_init)(void);
+ int (*crl_init)(void);
+ void *(*cert_get)(u_int8_t *, u_int32_t);
+ int (*cert_validate)(void *);
+ int (*cert_insert)(int, void *);
+ void (*cert_free)(void *);
+ int (*certreq_validate)(u_int8_t *, u_int32_t);
+ void *(*certreq_decode)(u_int8_t *, u_int32_t);
+ void (*free_aca)(void *);
+ int (*cert_obtain)(u_int8_t *, size_t, void *, u_int8_t **,
+ u_int32_t *);
+ int (*cert_get_key) (void *, void *);
+ int (*cert_get_subjects) (void *, int *, u_int8_t ***,
+ u_int32_t **);
+ void *(*cert_dup) (void *);
+ void (*cert_serialize) (void *, u_int8_t **, u_int32_t *);
+ char *(*cert_printable) (void *);
+ void *(*cert_from_printable) (char *);
+};
+
+/* The acceptable authority of cert request. */
+struct certreq_aca {
+ TAILQ_ENTRY(certreq_aca) link;
+
+ u_int16_t id;
+ struct cert_handler *handler;
+
+ /* If data is a null pointer, everything is acceptable. */
+ void *data;
+};
+
+struct certreq_aca *certreq_decode(u_int16_t, u_int8_t *, u_int32_t);
+void cert_free_subjects(int, u_int8_t **, u_int32_t *);
+struct cert_handler *cert_get(u_int16_t);
+int cert_init(void);
+int crl_init(void);
+
+#endif /* _CERT_H_ */
diff --git a/keyexchange/isakmpd-20041012/conf.c b/keyexchange/isakmpd-20041012/conf.c
new file mode 100644
index 0000000..0eaa1e9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/conf.c
@@ -0,0 +1,1123 @@
+/* $OpenBSD: conf.c,v 1.73 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000, 2001, 2002 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "sysdep.h"
+
+#include "app.h"
+#include "conf.h"
+#include "log.h"
+#include "monitor.h"
+#include "util.h"
+
+static char *conf_get_trans_str(int, char *, char *);
+static void conf_load_defaults(int);
+#if 0
+static int conf_find_trans_xf(int, char *);
+#endif
+
+struct conf_trans {
+ TAILQ_ENTRY(conf_trans) link;
+ int trans;
+ enum conf_op {
+ CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION
+ } op;
+ char *section;
+ char *tag;
+ char *value;
+ int override;
+ int is_default;
+};
+
+#define CONF_SECT_MAX 256
+
+TAILQ_HEAD(conf_trans_head, conf_trans) conf_trans_queue;
+
+/*
+ * Radix-64 Encoding.
+ */
+const u_int8_t bin2asc[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+const u_int8_t asc2bin[] =
+{
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 255, 255, 255, 255, 255, 255,
+ 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 255, 255, 255, 255, 255,
+ 255, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255
+};
+
+struct conf_binding {
+ LIST_ENTRY(conf_binding) link;
+ char *section;
+ char *tag;
+ char *value;
+ int is_default;
+};
+
+char *conf_path = CONFIG_FILE;
+LIST_HEAD(conf_bindings, conf_binding) conf_bindings[256];
+
+static char *conf_addr;
+static __inline__ u_int8_t
+conf_hash(char *s)
+{
+ u_int8_t hash = 0;
+
+ while (*s) {
+ hash = ((hash << 1) | (hash >> 7)) ^ tolower(*s);
+ s++;
+ }
+ return hash;
+}
+
+/*
+ * Insert a tag-value combination from LINE (the equal sign is at POS)
+ */
+static int
+conf_remove_now(char *section, char *tag)
+{
+ struct conf_binding *cb, *next;
+
+ for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb;
+ cb = next) {
+ next = LIST_NEXT(cb, link);
+ if (strcasecmp(cb->section, section) == 0
+ && strcasecmp(cb->tag, tag) == 0) {
+ LIST_REMOVE(cb, link);
+ LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section,
+ tag, cb->value));
+ free(cb->section);
+ free(cb->tag);
+ free(cb->value);
+ free(cb);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+conf_remove_section_now(char *section)
+{
+ struct conf_binding *cb, *next;
+ int unseen = 1;
+
+ for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb;
+ cb = next) {
+ next = LIST_NEXT(cb, link);
+ if (strcasecmp(cb->section, section) == 0) {
+ unseen = 0;
+ LIST_REMOVE(cb, link);
+ LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section,
+ cb->tag, cb->value));
+ free(cb->section);
+ free(cb->tag);
+ free(cb->value);
+ free(cb);
+ }
+ }
+ return unseen;
+}
+
+/*
+ * Insert a tag-value combination from LINE (the equal sign is at POS)
+ * into SECTION of our configuration database.
+ */
+static int
+conf_set_now(char *section, char *tag, char *value, int override,
+ int is_default)
+{
+ struct conf_binding *node = 0;
+
+ if (override)
+ conf_remove_now(section, tag);
+ else if (conf_get_str(section, tag)) {
+ if (!is_default)
+ log_print("conf_set_now: duplicate tag [%s]:%s, "
+ "ignoring...\n", section, tag);
+ return 1;
+ }
+ node = calloc(1, sizeof *node);
+ if (!node) {
+ log_error("conf_set_now: calloc (1, %lu) failed",
+ (unsigned long)sizeof *node);
+ return 1;
+ }
+ node->section = strdup(section);
+ node->tag = strdup(tag);
+ node->value = strdup(value);
+ node->is_default = is_default;
+
+ LIST_INSERT_HEAD(&conf_bindings[conf_hash(section)], node, link);
+ LOG_DBG((LOG_MISC, 95, "conf_set_now: [%s]:%s->%s", node->section,
+ node->tag, node->value));
+ return 0;
+}
+
+/*
+ * Parse the line LINE of SZ bytes. Skip Comments, recognize section
+ * headers and feed tag-value pairs into our configuration database.
+ */
+static void
+conf_parse_line(int trans, char *line, size_t sz)
+{
+ char *val;
+ size_t i;
+ int j;
+ static char *section = 0;
+ static int ln = 0;
+
+ ln++;
+
+ /* Lines starting with '#' or ';' are comments. */
+ if (*line == '#' || *line == ';')
+ return;
+
+ /* '[section]' parsing... */
+ if (*line == '[') {
+ for (i = 1; i < sz; i++)
+ if (line[i] == ']')
+ break;
+ if (section)
+ free(section);
+ if (i == sz) {
+ log_print("conf_parse_line: %d:"
+ "unmatched ']', ignoring until next section", ln);
+ section = 0;
+ return;
+ }
+ section = malloc(i);
+ if (!section) {
+ log_print("conf_parse_line: %d: malloc (%lu) failed",
+ ln, (unsigned long)i);
+ return;
+ }
+ strlcpy(section, line + 1, i);
+ return;
+ }
+ /* Deal with assignments. */
+ for (i = 0; i < sz; i++)
+ if (line[i] == '=') {
+ /* If no section, we are ignoring the lines. */
+ if (!section) {
+ log_print("conf_parse_line: %d: ignoring line "
+ "due to no section", ln);
+ return;
+ }
+ line[strcspn(line, " \t=")] = '\0';
+ val = line + i + 1 + strspn(line + i + 1, " \t");
+ /* Skip trailing whitespace, if any */
+ for (j = sz - (val - line) - 1; j > 0 &&
+ isspace(val[j]); j--)
+ val[j] = '\0';
+ /* XXX Perhaps should we not ignore errors? */
+ conf_set(trans, section, line, val, 0, 0);
+ return;
+ }
+ /* Other non-empty lines are weird. */
+ i = strspn(line, " \t");
+ if (line[i])
+ log_print("conf_parse_line: %d: syntax error", ln);
+}
+
+/* Parse the mapped configuration file. */
+static void
+conf_parse(int trans, char *buf, size_t sz)
+{
+ char *cp = buf;
+ char *bufend = buf + sz;
+ char *line;
+
+ line = cp;
+ while (cp < bufend) {
+ if (*cp == '\n') {
+ /* Check for escaped newlines. */
+ if (cp > buf && *(cp - 1) == '\\')
+ *(cp - 1) = *cp = ' ';
+ else {
+ *cp = '\0';
+ conf_parse_line(trans, line, cp - line);
+ line = cp + 1;
+ }
+ }
+ cp++;
+ }
+ if (cp != line)
+ log_print("conf_parse: last line unterminated, ignored.");
+}
+
+/*
+ * Auto-generate default configuration values for the transforms and
+ * suites the user wants.
+ *
+ * Resulting section names can be:
+ * For main mode:
+ * {DES,BLF,3DES,CAST,AES}-{MD5,SHA}[-GRP{1,2,5,14}][-{DSS,RSA_SIG}]
+ * For quick mode:
+ * QM-{proto}[-TRP]-{cipher}[-{hash}][-PFS[-{group}]]-SUITE
+ * where
+ * {proto} = ESP, AH
+ * {cipher} = DES, 3DES, CAST, BLF, AES
+ * {hash} = MD5, SHA, RIPEMD, SHA2-{-256,384,512}
+ * {group} = GRP1, GRP2, GRP5, GRP14
+ *
+ * DH group defaults to MODP_1024.
+ *
+ * XXX We may want to support USE_BLOWFISH, USE_TRIPLEDES, etc...
+ * XXX No EC2N DH support here yet.
+ */
+
+/* Find the value for a section+tag in the transaction list. */
+static char *
+conf_get_trans_str(int trans, char *section, char *tag)
+{
+ struct conf_trans *node, *nf = 0;
+
+ for (node = TAILQ_FIRST(&conf_trans_queue); node;
+ node = TAILQ_NEXT(node, link))
+ if (node->trans == trans && strcasecmp(section, node->section)
+ == 0 && strcasecmp(tag, node->tag) == 0) {
+ if (!nf)
+ nf = node;
+ else if (node->override)
+ nf = node;
+ }
+ return nf ? nf->value : 0;
+}
+
+#if 0
+/* XXX Currently unused. */
+static int
+conf_find_trans_xf(int phase, char *xf)
+{
+ struct conf_trans *node;
+ char *p;
+
+ /* Find the relevant transforms and suites, if any. */
+ for (node = TAILQ_FIRST(&conf_trans_queue); node;
+ node = TAILQ_NEXT(node, link))
+ if ((phase == 1 && strcmp("Transforms", node->tag) == 0) ||
+ (phase == 2 && strcmp("Suites", node->tag) == 0)) {
+ p = node->value;
+ while ((p = strstr(p, xf)) != NULL)
+ if (*(p + strlen(p)) &&
+ *(p + strlen(p)) != ',')
+ p += strlen(p);
+ else
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static void
+conf_load_defaults_mm(int tr, char *mme, char *mmh, char *mma, char *dhg,
+ char *mme_p, char *mma_p, char *dhg_p)
+{
+ char sect[CONF_SECT_MAX];
+
+ snprintf(sect, sizeof sect, "%s-%s%s%s", mme_p, mmh, dhg_p, mma_p);
+
+ LOG_DBG((LOG_MISC, 95, "conf_load_defaults_mm: main mode %s", sect));
+
+ conf_set(tr, sect, "ENCRYPTION_ALGORITHM", mme, 0, 1);
+ if (strcmp(mme, "BLOWFISH_CBC") == 0)
+ conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0,
+ 1);
+ else if (strcmp(mme, "AES_CBC") == 0)
+ conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_AES_KEYLEN, 0,
+ 1);
+
+ conf_set(tr, sect, "HASH_ALGORITHM", mmh, 0, 1);
+ conf_set(tr, sect, "AUTHENTICATION_METHOD", mma, 0, 1);
+ conf_set(tr, sect, "GROUP_DESCRIPTION", dhg, 0, 1);
+ conf_set(tr, sect, "Life", CONF_DFLT_TAG_LIFE_MAIN_MODE, 0, 1);
+}
+
+static void
+conf_load_defaults_qm(int tr, char *qme, char *qmh, char *dhg, char *qme_p,
+ char *qmh_p, char *dhg_p, int proto, int mode, int pfs)
+{
+ char sect[CONF_SECT_MAX], tmp[CONF_SECT_MAX];
+
+ /* Helper #defines, incl abbreviations. */
+#define PROTO(x) ((x) ? "AH" : "ESP")
+#define PFS(x) ((x) ? "-PFS" : "")
+#define MODE(x) ((x) ? "TRANSPORT" : "TUNNEL")
+#define MODE_p(x) ((x) ? "-TRP" : "")
+
+ if (proto == 1 && strcmp(qmh, "NONE") == 0) /* AH */
+ return;
+
+ snprintf(tmp, sizeof tmp, "QM-%s%s%s%s%s%s", PROTO(proto),
+ MODE_p(mode), qme_p, qmh_p, PFS(pfs), dhg_p);
+
+ strlcpy(sect, tmp, CONF_SECT_MAX);
+ strlcat(sect, "-SUITE", CONF_SECT_MAX);
+
+ LOG_DBG((LOG_MISC, 95, "conf_load_defaults_qm: quick mode %s", sect));
+
+ conf_set(tr, sect, "Protocols", tmp, 0, 1);
+ snprintf(sect, sizeof sect, "IPSEC_%s", PROTO(proto));
+ conf_set(tr, tmp, "PROTOCOL_ID", sect, 0, 1);
+ strlcpy(sect, tmp, CONF_SECT_MAX);
+ strlcat(sect, "-XF", CONF_SECT_MAX);
+ conf_set(tr, tmp, "Transforms", sect, 0, 1);
+
+ /*
+ * XXX For now, defaults
+ * contain one xf per protocol.
+ */
+ conf_set(tr, sect, "TRANSFORM_ID", qme, 0, 1);
+ if (strcmp(qme ,"BLOWFISH") == 0)
+ conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0,
+ 1);
+ else if (strcmp(qme ,"AES") == 0)
+ conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_AES_KEYLEN, 0,
+ 1);
+ conf_set(tr, sect, "ENCAPSULATION_MODE", MODE(mode), 0, 1);
+ if (strcmp(qmh, "NONE")) {
+ conf_set(tr, sect, "AUTHENTICATION_ALGORITHM", qmh, 0, 1);
+
+ /* XXX Another shortcut to keep length down */
+ if (pfs)
+ conf_set(tr, sect, "GROUP_DESCRIPTION", dhg, 0, 1);
+ }
+
+ /* XXX Lifetimes depending on enc/auth strength? */
+ conf_set(tr, sect, "Life", CONF_DFLT_TAG_LIFE_QUICK_MODE, 0, 1);
+}
+
+static void
+conf_load_defaults(int tr)
+{
+ int enc, auth, hash, group, proto, mode, pfs;
+ char *dflt;
+
+ char *mm_auth[] = {"PRE_SHARED", "DSS", "RSA_SIG", 0};
+ char *mm_auth_p[] = {"", "-DSS", "-RSA_SIG", 0};
+ char *mm_hash[] = {"MD5", "SHA", 0};
+ char *mm_enc[] = {"DES_CBC", "BLOWFISH_CBC", "3DES_CBC", "CAST_CBC",
+ "AES_CBC", 0};
+ char *mm_enc_p[] = {"DES", "BLF", "3DES", "CAST", "AES", 0};
+ char *dhgroup[] = {"MODP_1024", "MODP_768", "MODP_1024",
+ "MODP_1536", "MODP_2048", 0};
+ char *dhgroup_p[] = {"", "-GRP1", "-GRP2", "-GRP5", "-GRP14", 0};
+ char *qm_enc[] = {"DES", "3DES", "CAST", "BLOWFISH", "AES", 0};
+ char *qm_enc_p[] = {"-DES", "-3DES", "-CAST", "-BLF", "-AES", 0};
+ char *qm_hash[] = {"HMAC_MD5", "HMAC_SHA", "HMAC_RIPEMD",
+ "HMAC_SHA2_256", "HMAC_SHA2_384", "HMAC_SHA2_512", "NONE",
+ 0};
+ char *qm_hash_p[] = {"-MD5", "-SHA", "-RIPEMD", "-SHA2-256",
+ "-SHA2-384", "-SHA2-512", "", 0};
+
+ /* General and X509 defaults */
+ conf_set(tr, "General", "Retransmits", CONF_DFLT_RETRANSMITS, 0, 1);
+ conf_set(tr, "General", "Exchange-max-time", CONF_DFLT_EXCH_MAX_TIME,
+ 0, 1);
+ conf_set(tr, "General", "Use-Keynote", CONF_DFLT_USE_KEYNOTE, 0, 1);
+ conf_set(tr, "General", "Policy-file", CONF_DFLT_POLICY_FILE, 0, 1);
+ conf_set(tr, "General", "Pubkey-directory", CONF_DFLT_PUBKEY_DIR, 0,
+ 1);
+
+#ifdef USE_X509
+ conf_set(tr, "X509-certificates", "CA-directory",
+ CONF_DFLT_X509_CA_DIR, 0, 1);
+ conf_set(tr, "X509-certificates", "Cert-directory",
+ CONF_DFLT_X509_CERT_DIR, 0, 1);
+ conf_set(tr, "X509-certificates", "Private-key",
+ CONF_DFLT_X509_PRIVATE_KEY, 0, 1);
+ conf_set(tr, "X509-certificates", "CRL-directory",
+ CONF_DFLT_X509_CRL_DIR, 0, 1);
+#endif
+
+#ifdef USE_KEYNOTE
+ conf_set(tr, "KeyNote", "Credential-directory",
+ CONF_DFLT_KEYNOTE_CRED_DIR, 0, 1);
+#endif
+
+ /* Lifetimes. XXX p1/p2 vs main/quick mode may be unclear. */
+ dflt = conf_get_trans_str(tr, "General", "Default-phase-1-lifetime");
+ conf_set(tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_TYPE",
+ CONF_DFLT_TYPE_LIFE_MAIN_MODE, 0, 1);
+ conf_set(tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_DURATION",
+ (dflt ? dflt : CONF_DFLT_VAL_LIFE_MAIN_MODE), 0, 1);
+
+ dflt = conf_get_trans_str(tr, "General", "Default-phase-2-lifetime");
+ conf_set(tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_TYPE",
+ CONF_DFLT_TYPE_LIFE_QUICK_MODE, 0, 1);
+ conf_set(tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_DURATION",
+ (dflt ? dflt : CONF_DFLT_VAL_LIFE_QUICK_MODE), 0, 1);
+
+ /* Default Phase-1 Configuration section */
+ conf_set(tr, CONF_DFLT_TAG_PHASE1_CONFIG, "EXCHANGE_TYPE",
+ CONF_DFLT_PHASE1_EXCH_TYPE, 0, 1);
+ conf_set(tr, CONF_DFLT_TAG_PHASE1_CONFIG, "Transforms",
+ CONF_DFLT_PHASE1_TRANSFORMS, 0, 1);
+
+ /* Main modes */
+ for (enc = 0; mm_enc[enc]; enc++)
+ for (hash = 0; mm_hash[hash]; hash++)
+ for (auth = 0; mm_auth[auth]; auth++)
+ for (group = 0; dhgroup_p[group]; group++)
+ conf_load_defaults_mm (tr, mm_enc[enc],
+ mm_hash[hash], mm_auth[auth],
+ dhgroup[group], mm_enc_p[enc],
+ mm_auth_p[auth], dhgroup_p[group]);
+
+ /* Setup a default Phase 1 entry */
+ conf_set(tr, "Phase 1", "Default", "Default-phase-1", 0, 1);
+ conf_set(tr, "Default-phase-1", "Phase", "1", 0, 1);
+ conf_set(tr, "Default-phase-1", "Configuration",
+ "Default-phase-1-configuration", 0, 1);
+ dflt = conf_get_trans_str(tr, "General", "Default-phase-1-ID");
+ if (dflt)
+ conf_set(tr, "Default-phase-1", "ID", dflt, 0, 1);
+
+ /* Quick modes */
+ for (enc = 0; qm_enc[enc]; enc++)
+ for (proto = 0; proto < 2; proto++)
+ for (mode = 0; mode < 2; mode++)
+ for (pfs = 0; pfs < 2; pfs++)
+ for (hash = 0; qm_hash[hash]; hash++)
+ for (group = 0;
+ dhgroup_p[group]; group++)
+ conf_load_defaults_qm(
+ tr, qm_enc[enc],
+ qm_hash[hash],
+ dhgroup[group],
+ qm_enc_p[enc],
+ qm_hash_p[hash],
+ dhgroup_p[group],
+ proto, mode, pfs);
+}
+
+void
+conf_init(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
+ LIST_INIT(&conf_bindings[i]);
+ TAILQ_INIT(&conf_trans_queue);
+ conf_reinit();
+}
+
+/* Open the config file and map it into our address space, then parse it. */
+void
+conf_reinit(void)
+{
+ struct conf_binding *cb = 0;
+ int fd, trans;
+ unsigned int i;
+ size_t sz;
+ char *new_conf_addr = 0;
+
+ if ((fd = monitor_open(conf_path, O_RDONLY, 0)) != -1) {
+ if (check_file_secrecy_fd(fd, conf_path, &sz))
+ goto fail;
+
+ new_conf_addr = malloc(sz);
+ if (!new_conf_addr) {
+ log_error("conf_reinit: malloc (%lu) failed",
+ (unsigned long)sz);
+ goto fail;
+ }
+ /* XXX I assume short reads won't happen here. */
+ if (read(fd, new_conf_addr, sz) != (int)sz) {
+ log_error("conf_reinit: read (%d, %p, %lu) failed",
+ fd, new_conf_addr, (unsigned long)sz);
+ goto fail;
+ }
+ close(fd);
+
+ trans = conf_begin();
+
+ /* XXX Should we not care about errors and rollback? */
+ conf_parse(trans, new_conf_addr, sz);
+ } else {
+ if (errno != ENOENT)
+ log_error("conf_reinit: open(\"%s\", O_RDONLY, 0) "
+ "failed", conf_path);
+
+ trans = conf_begin();
+ }
+
+ /* Load default configuration values. */
+ conf_load_defaults(trans);
+
+ /* Free potential existing configuration. */
+ if (conf_addr) {
+ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0];
+ i++)
+ for (cb = LIST_FIRST(&conf_bindings[i]); cb;
+ cb = LIST_FIRST(&conf_bindings[i]))
+ conf_remove_now(cb->section, cb->tag);
+ free(conf_addr);
+ }
+ conf_end(trans, 1);
+ conf_addr = new_conf_addr;
+ return;
+
+fail:
+ if (new_conf_addr)
+ free(new_conf_addr);
+ close(fd);
+}
+
+/*
+ * Return the numeric value denoted by TAG in section SECTION or DEF
+ * if that tag does not exist.
+ */
+int
+conf_get_num(char *section, char *tag, int def)
+{
+ char *value = conf_get_str(section, tag);
+
+ if (value)
+ return atoi(value);
+ return def;
+}
+
+/*
+ * Return the socket endpoint address denoted by TAG in SECTION as a
+ * struct sockaddr. It is the callers responsibility to deallocate
+ * this structure when it is finished with it.
+ */
+struct sockaddr *
+conf_get_address(char *section, char *tag)
+{
+ char *value = conf_get_str(section, tag);
+ struct sockaddr *sa;
+
+ if (!value)
+ return 0;
+ if (text2sockaddr(value, 0, &sa) == -1)
+ return 0;
+ return sa;
+}
+
+/* Validate X according to the range denoted by TAG in section SECTION. */
+int
+conf_match_num(char *section, char *tag, int x)
+{
+ char *value = conf_get_str(section, tag);
+ int val, min, max, n;
+
+ if (!value)
+ return 0;
+ n = sscanf(value, "%d,%d:%d", &val, &min, &max);
+ switch (n) {
+ case 1:
+ LOG_DBG((LOG_MISC, 95, "conf_match_num: %s:%s %d==%d?",
+ section, tag, val, x));
+ return x == val;
+ case 3:
+ LOG_DBG((LOG_MISC, 95, "conf_match_num: %s:%s %d<=%d<=%d?",
+ section, tag, min, x, max));
+ return min <= x && max >= x;
+ default:
+ log_error("conf_match_num: section %s tag %s: invalid number "
+ "spec %s", section, tag, value);
+ }
+ return 0;
+}
+
+/* Return the string value denoted by TAG in section SECTION. */
+char *
+conf_get_str(char *section, char *tag)
+{
+ struct conf_binding *cb;
+
+ for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb;
+ cb = LIST_NEXT(cb, link))
+ if (strcasecmp(section, cb->section) == 0 &&
+ strcasecmp(tag, cb->tag) == 0) {
+ LOG_DBG((LOG_MISC, 95, "conf_get_str: [%s]:%s->%s",
+ section, tag, cb->value));
+ return cb->value;
+ }
+ LOG_DBG((LOG_MISC, 95,
+ "conf_get_str: configuration value not found [%s]:%s", section,
+ tag));
+ return 0;
+}
+
+/*
+ * Build a list of string values out of the comma separated value denoted by
+ * TAG in SECTION.
+ */
+struct conf_list *
+conf_get_list(char *section, char *tag)
+{
+ char *liststr = 0, *p, *field, *t;
+ struct conf_list *list = 0;
+ struct conf_list_node *node;
+
+ list = malloc(sizeof *list);
+ if (!list)
+ goto cleanup;
+ TAILQ_INIT(&list->fields);
+ list->cnt = 0;
+ liststr = conf_get_str(section, tag);
+ if (!liststr)
+ goto cleanup;
+ liststr = strdup(liststr);
+ if (!liststr)
+ goto cleanup;
+ p = liststr;
+ while ((field = strsep(&p, ",")) != NULL) {
+ /* Skip leading whitespace */
+ while (isspace(*field))
+ field++;
+ /* Skip trailing whitespace */
+ if (p)
+ for (t = p - 1; t > field && isspace(*t); t--)
+ *t = '\0';
+ if (*field == '\0') {
+ log_print("conf_get_list: empty field, ignoring...");
+ continue;
+ }
+ list->cnt++;
+ node = calloc(1, sizeof *node);
+ if (!node)
+ goto cleanup;
+ node->field = strdup(field);
+ if (!node->field)
+ goto cleanup;
+ TAILQ_INSERT_TAIL(&list->fields, node, link);
+ }
+ free(liststr);
+ return list;
+
+cleanup:
+ if (list)
+ conf_free_list(list);
+ if (liststr)
+ free(liststr);
+ return 0;
+}
+
+struct conf_list *
+conf_get_tag_list(char *section)
+{
+ struct conf_list *list = 0;
+ struct conf_list_node *node;
+ struct conf_binding *cb;
+
+ list = malloc(sizeof *list);
+ if (!list)
+ goto cleanup;
+ TAILQ_INIT(&list->fields);
+ list->cnt = 0;
+ for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb;
+ cb = LIST_NEXT(cb, link))
+ if (strcasecmp(section, cb->section) == 0) {
+ list->cnt++;
+ node = calloc(1, sizeof *node);
+ if (!node)
+ goto cleanup;
+ node->field = strdup(cb->tag);
+ if (!node->field)
+ goto cleanup;
+ TAILQ_INSERT_TAIL(&list->fields, node, link);
+ }
+ return list;
+
+cleanup:
+ if (list)
+ conf_free_list(list);
+ return 0;
+}
+
+/* Decode a PEM encoded buffer. */
+int
+conf_decode_base64(u_int8_t *out, u_int32_t *len, u_char *buf)
+{
+ u_int32_t c = 0;
+ u_int8_t c1, c2, c3, c4;
+
+ while (*buf) {
+ if (*buf > 127 || (c1 = asc2bin[*buf]) == 255)
+ return 0;
+ buf++;
+
+ if (*buf > 127 || (c2 = asc2bin[*buf]) == 255)
+ return 0;
+ buf++;
+
+ if (*buf == '=') {
+ c3 = c4 = 0;
+ c++;
+
+ /* Check last four bit */
+ if (c2 & 0xF)
+ return 0;
+
+ if (strcmp((char *)buf, "==") == 0)
+ buf++;
+ else
+ return 0;
+ } else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255)
+ return 0;
+ else {
+ if (*++buf == '=') {
+ c4 = 0;
+ c += 2;
+
+ /* Check last two bit */
+ if (c3 & 3)
+ return 0;
+
+ if (strcmp((char *)buf, "="))
+ return 0;
+
+ } else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255)
+ return 0;
+ else
+ c += 3;
+ }
+
+ buf++;
+ *out++ = (c1 << 2) | (c2 >> 4);
+ *out++ = (c2 << 4) | (c3 >> 2);
+ *out++ = (c3 << 6) | c4;
+ }
+
+ *len = c;
+ return 1;
+
+}
+
+void
+conf_free_list(struct conf_list *list)
+{
+ struct conf_list_node *node = TAILQ_FIRST(&list->fields);
+
+ while (node) {
+ TAILQ_REMOVE(&list->fields, node, link);
+ if (node->field)
+ free(node->field);
+ free(node);
+ node = TAILQ_FIRST(&list->fields);
+ }
+ free(list);
+}
+
+int
+conf_begin(void)
+{
+ static int seq = 0;
+
+ return ++seq;
+}
+
+static struct conf_trans *
+conf_trans_node(int transaction, enum conf_op op)
+{
+ struct conf_trans *node;
+
+ node = calloc(1, sizeof *node);
+ if (!node) {
+ log_error("conf_trans_node: calloc (1, %lu) failed",
+ (unsigned long)sizeof *node);
+ return 0;
+ }
+ node->trans = transaction;
+ node->op = op;
+ TAILQ_INSERT_TAIL(&conf_trans_queue, node, link);
+ return node;
+}
+
+/* Queue a set operation. */
+int
+conf_set(int transaction, char *section, char *tag, char *value, int override,
+ int is_default)
+{
+ struct conf_trans *node;
+
+ node = conf_trans_node(transaction, CONF_SET);
+ if (!node)
+ return 1;
+ node->section = strdup(section);
+ if (!node->section) {
+ log_error("conf_set: strdup (\"%s\") failed", section);
+ goto fail;
+ }
+ node->tag = strdup(tag);
+ if (!node->tag) {
+ log_error("conf_set: strdup (\"%s\") failed", tag);
+ goto fail;
+ }
+ node->value = strdup(value);
+ if (!node->value) {
+ log_error("conf_set: strdup (\"%s\") failed", value);
+ goto fail;
+ }
+ node->override = override;
+ node->is_default = is_default;
+ return 0;
+
+fail:
+ if (node->tag)
+ free(node->tag);
+ if (node->section)
+ free(node->section);
+ if (node)
+ free(node);
+ return 1;
+}
+
+/* Queue a remove operation. */
+int
+conf_remove(int transaction, char *section, char *tag)
+{
+ struct conf_trans *node;
+
+ node = conf_trans_node(transaction, CONF_REMOVE);
+ if (!node)
+ goto fail;
+ node->section = strdup(section);
+ if (!node->section) {
+ log_error("conf_remove: strdup (\"%s\") failed", section);
+ goto fail;
+ }
+ node->tag = strdup(tag);
+ if (!node->tag) {
+ log_error("conf_remove: strdup (\"%s\") failed", tag);
+ goto fail;
+ }
+ return 0;
+
+fail:
+ if (node->section)
+ free(node->section);
+ if (node)
+ free(node);
+ return 1;
+}
+
+/* Queue a remove section operation. */
+int
+conf_remove_section(int transaction, char *section)
+{
+ struct conf_trans *node;
+
+ node = conf_trans_node(transaction, CONF_REMOVE_SECTION);
+ if (!node)
+ goto fail;
+ node->section = strdup(section);
+ if (!node->section) {
+ log_error("conf_remove_section: strdup (\"%s\") failed",
+ section);
+ goto fail;
+ }
+ return 0;
+
+fail:
+ if (node)
+ free(node);
+ return 1;
+}
+
+/* Execute all queued operations for this transaction. Cleanup. */
+int
+conf_end(int transaction, int commit)
+{
+ struct conf_trans *node, *next;
+
+ for (node = TAILQ_FIRST(&conf_trans_queue); node; node = next) {
+ next = TAILQ_NEXT(node, link);
+ if (node->trans == transaction) {
+ if (commit)
+ switch (node->op) {
+ case CONF_SET:
+ conf_set_now(node->section, node->tag,
+ node->value, node->override,
+ node->is_default);
+ break;
+ case CONF_REMOVE:
+ conf_remove_now(node->section,
+ node->tag);
+ break;
+ case CONF_REMOVE_SECTION:
+ conf_remove_section_now(node->section);
+ break;
+ default:
+ log_print("conf_end: unknown "
+ "operation: %d", node->op);
+ }
+ TAILQ_REMOVE(&conf_trans_queue, node, link);
+ if (node->section)
+ free(node->section);
+ if (node->tag)
+ free(node->tag);
+ if (node->value)
+ free(node->value);
+ free(node);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Dump running configuration upon SIGUSR1.
+ * Configuration is "stored in reverse order", so reverse it again.
+ */
+struct dumper {
+ char *s, *v;
+ struct dumper *next;
+};
+
+static void
+conf_report_dump(struct dumper *node)
+{
+ /* Recursive, cleanup when we're done. */
+
+ if (node->next)
+ conf_report_dump(node->next);
+
+ if (node->v)
+ LOG_DBG((LOG_REPORT, 0, "%s=\t%s", node->s, node->v));
+ else if (node->s) {
+ LOG_DBG((LOG_REPORT, 0, "%s", node->s));
+ if (strlen(node->s) > 0)
+ free(node->s);
+ }
+ free(node);
+}
+
+void
+conf_report(void)
+{
+ struct conf_binding *cb, *last = 0;
+ unsigned int i, len;
+ char *current_section = (char *)0;
+ struct dumper *dumper, *dnode;
+
+ dumper = dnode = (struct dumper *)calloc(1, sizeof *dumper);
+ if (!dumper)
+ goto mem_fail;
+
+ LOG_DBG((LOG_REPORT, 0, "conf_report: dumping running configuration"));
+
+ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
+ for (cb = LIST_FIRST(&conf_bindings[i]); cb;
+ cb = LIST_NEXT(cb, link)) {
+ if (!cb->is_default) {
+ /* Dump this entry. */
+ if (!current_section || strcmp(cb->section,
+ current_section)) {
+ if (current_section) {
+ len = strlen(current_section)
+ + 3;
+ dnode->s = malloc(len);
+ if (!dnode->s)
+ goto mem_fail;
+
+ snprintf(dnode->s, len, "[%s]",
+ current_section);
+ dnode->next = (struct dumper *)
+ calloc(1,
+ sizeof(struct dumper));
+ dnode = dnode->next;
+ if (!dnode)
+ goto mem_fail;
+
+ dnode->s = "";
+ dnode->next = (struct dumper *)
+ calloc(1,
+ sizeof(struct dumper));
+ dnode = dnode->next;
+ if (!dnode)
+ goto mem_fail;
+ }
+ current_section = cb->section;
+ }
+ dnode->s = cb->tag;
+ dnode->v = cb->value;
+ dnode->next = (struct dumper *)
+ calloc(1, sizeof(struct dumper));
+ dnode = dnode->next;
+ if (!dnode)
+ goto mem_fail;
+ last = cb;
+ }
+ }
+
+ if (last) {
+ len = strlen(last->section) + 3;
+ dnode->s = malloc(len);
+ if (!dnode->s)
+ goto mem_fail;
+ snprintf(dnode->s, len, "[%s]", last->section);
+ }
+ conf_report_dump(dumper);
+
+ return;
+
+mem_fail:
+ log_error("conf_report: malloc/calloc failed");
+ while ((dnode = dumper) != 0) {
+ dumper = dumper->next;
+ if (dnode->s)
+ free(dnode->s);
+ free(dnode);
+ }
+}
diff --git a/keyexchange/isakmpd-20041012/conf.h b/keyexchange/isakmpd-20041012/conf.h
new file mode 100644
index 0000000..7c66620
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/conf.h
@@ -0,0 +1,103 @@
+/* $OpenBSD: conf.h,v 1.30 2004/06/25 20:25:34 hshoexer Exp $ */
+/* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000, 2003 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CONF_H_
+#define _CONF_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <stdio.h>
+
+#define ISAKMPD_ROOT "/etc/isakmpd/"
+
+#define CONFIG_FILE ISAKMPD_ROOT "isakmpd.conf"
+
+/* Default values for autogenerated part of our configuration. */
+#define CONF_DFLT_TAG_LIFE_MAIN_MODE "LIFE_MAIN_MODE"
+#define CONF_DFLT_TYPE_LIFE_MAIN_MODE "SECONDS"
+#define CONF_DFLT_VAL_LIFE_MAIN_MODE "3600,60:86400"
+
+#define CONF_DFLT_TAG_LIFE_QUICK_MODE "LIFE_QUICK_MODE"
+#define CONF_DFLT_TYPE_LIFE_QUICK_MODE "SECONDS"
+#define CONF_DFLT_VAL_LIFE_QUICK_MODE "1200,60:86400"
+
+#define CONF_DFLT_VAL_BLF_KEYLEN "128,96:192"
+#define CONF_DFLT_VAL_AES_KEYLEN "128,128:256"
+
+#define CONF_DFLT_RETRANSMITS "3"
+#define CONF_DFLT_EXCH_MAX_TIME "120"
+
+#define CONF_DFLT_USE_KEYNOTE "yes"
+#define CONF_DFLT_POLICY_FILE ISAKMPD_ROOT "isakmpd.policy"
+
+#define CONF_DFLT_X509_CA_DIR ISAKMPD_ROOT "ca/"
+#define CONF_DFLT_X509_CERT_DIR ISAKMPD_ROOT "certs/"
+#define CONF_DFLT_X509_PRIVATE_KEY ISAKMPD_ROOT "private/local.key"
+#define CONF_DFLT_X509_CRL_DIR ISAKMPD_ROOT "crls/"
+#define CONF_DFLT_PUBKEY_DIR ISAKMPD_ROOT "pubkeys/"
+#define CONF_DFLT_KEYNOTE_CRED_DIR ISAKMPD_ROOT "keynote/"
+
+#define CONF_DFLT_TAG_PHASE1_CONFIG "Default-phase-1-configuration"
+#define CONF_DFLT_PHASE1_EXCH_TYPE "ID_PROT"
+#define CONF_DFLT_PHASE1_TRANSFORMS "3DES-SHA-RSA_SIG"
+
+struct conf_list_node {
+ TAILQ_ENTRY(conf_list_node) link;
+ char *field;
+};
+
+struct conf_list {
+ size_t cnt;
+ TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields;
+};
+
+extern char *conf_path;
+
+extern int conf_begin(void);
+extern int conf_decode_base64(u_int8_t *, u_int32_t *, u_char *);
+extern int conf_end(int, int);
+extern void conf_free_list(struct conf_list *);
+extern struct sockaddr *conf_get_address(char *, char *);
+extern struct conf_list *conf_get_list(char *, char *);
+extern struct conf_list *conf_get_tag_list(char *);
+extern int conf_get_num(char *, char *, int);
+extern char *conf_get_str(char *, char *);
+extern void conf_init(void);
+extern int conf_match_num(char *, char *, int);
+extern void conf_reinit(void);
+extern int conf_remove(int, char *, char *);
+extern int conf_remove_section(int, char *);
+extern int conf_set(int, char *, char *, char *, int, int);
+extern void conf_report(void);
+
+#endif /* _CONF_H_ */
diff --git a/keyexchange/isakmpd-20041012/connection.c b/keyexchange/isakmpd-20041012/connection.c
new file mode 100644
index 0000000..94373ad
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/connection.c
@@ -0,0 +1,449 @@
+/* $OpenBSD: connection.c,v 1.29 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: connection.c,v 1.28 2000/11/23 12:21:18 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999 Hakan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "connection.h"
+#include "doi.h"
+#include "ipsec.h"
+
+/* XXX isakmp.h only required for compare_ids(). */
+#include "isakmp.h"
+
+#include "log.h"
+#include "timer.h"
+#include "util.h"
+
+/* How often should we check that connections we require to be up, are up? */
+#define CHECK_INTERVAL 60
+
+static void connection_passive_teardown(char *);
+
+struct connection {
+ TAILQ_ENTRY(connection) link;
+ char *name;
+ struct event *ev;
+};
+
+struct connection_passive {
+ TAILQ_ENTRY(connection_passive) link;
+ char *name;
+ u_int8_t *local_id, *remote_id;
+ size_t local_sz, remote_sz;
+
+#if 0
+ /* XXX Potential additions to 'connection_passive'. */
+ char *isakmp_peer;
+ struct sa *sa; /* XXX "Soft" ref to active sa? */
+ struct timeval sa_expiration; /* XXX *sa may expire. */
+#endif
+};
+
+TAILQ_HEAD(connection_head, connection) connections;
+TAILQ_HEAD(passive_head, connection_passive) connections_passive;
+
+/*
+ * This is where we setup all the connections we want there right from the
+ * start.
+ */
+void
+connection_init(void)
+{
+ struct conf_list *conns, *attrs;
+ struct conf_list_node *conn, *attr = NULL;
+
+ /*
+ * Passive connections normally include: all "active" connections that
+ * are not flagged "Active-Only", plus all connections listed in
+ * the 'Passive-Connections' list.
+ */
+ TAILQ_INIT(&connections);
+ TAILQ_INIT(&connections_passive);
+
+ conns = conf_get_list("Phase 2", "Connections");
+ if (conns) {
+ for (conn = TAILQ_FIRST(&conns->fields); conn;
+ conn = TAILQ_NEXT(conn, link)) {
+ if (connection_setup(conn->field))
+ log_print("connection_init: could not setup "
+ "\"%s\"", conn->field);
+
+ /* XXX Break/abort here if connection_setup failed? */
+
+ /*
+ * XXX This code (i.e. the attribute lookup) seems
+ * like a likely candidate for factoring out into a
+ * function of its own.
+ */
+ attrs = conf_get_list(conn->field, "Flags");
+ if (attrs)
+ for (attr = TAILQ_FIRST(&attrs->fields); attr;
+ attr = TAILQ_NEXT(attr, link))
+ if (strcasecmp("active-only",
+ attr->field) == 0)
+ break;
+ if (!attrs || (attrs && !attr))
+ if (connection_record_passive(conn->field))
+ log_print("connection_init: could not "
+ "record connection \"%s\"",
+ conn->field);
+ if (attrs)
+ conf_free_list(attrs);
+
+ }
+ conf_free_list(conns);
+ }
+ conns = conf_get_list("Phase 2", "Passive-Connections");
+ if (conns) {
+ for (conn = TAILQ_FIRST(&conns->fields); conn;
+ conn = TAILQ_NEXT(conn, link))
+ if (connection_record_passive(conn->field))
+ log_print("connection_init: could not record "
+ "passive connection \"%s\"", conn->field);
+ conf_free_list(conns);
+ }
+}
+
+/* Check the connection in VCONN and schedule another check later. */
+static void
+connection_checker(void *vconn)
+{
+ struct timeval now;
+ struct connection *conn = vconn;
+
+ gettimeofday(&now, 0);
+ now.tv_sec += conf_get_num("General", "check-interval",
+ CHECK_INTERVAL);
+ conn->ev = timer_add_event("connection_checker",
+ connection_checker, conn, &now);
+ if (!conn->ev)
+ log_print("connection_checker: could not add timer event");
+ sysdep_connection_check(conn->name);
+}
+
+/* Find the connection named NAME. */
+static struct connection *
+connection_lookup(char *name)
+{
+ struct connection *conn;
+
+ for (conn = TAILQ_FIRST(&connections); conn;
+ conn = TAILQ_NEXT(conn, link))
+ if (strcasecmp(conn->name, name) == 0)
+ return conn;
+ return 0;
+}
+
+/* Does the connection named NAME exist? */
+int
+connection_exist(char *name)
+{
+ return (connection_lookup(name) != 0);
+}
+
+/* Find the passive connection named NAME. */
+static struct connection_passive *
+connection_passive_lookup_by_name(char *name)
+{
+ struct connection_passive *conn;
+
+ for (conn = TAILQ_FIRST(&connections_passive); conn;
+ conn = TAILQ_NEXT(conn, link))
+ if (strcasecmp(conn->name, name) == 0)
+ return conn;
+ return 0;
+}
+
+/*
+ * IDs of different types cannot be the same.
+ * XXX Rename to ipsec_compare_id, and move to ipsec.c ?
+ */
+static int
+compare_ids(u_int8_t *id1, u_int8_t *id2, size_t idlen)
+{
+ int id1_type, id2_type;
+
+ id1_type = GET_ISAKMP_ID_TYPE(id1);
+ id2_type = GET_ISAKMP_ID_TYPE(id2);
+
+ return id1_type == id2_type ? memcmp(id1 + ISAKMP_ID_DATA_OFF,
+ id2 + ISAKMP_ID_DATA_OFF, idlen - ISAKMP_ID_DATA_OFF) : -1;
+}
+
+/* Find the connection named with matching IDs. */
+char *
+connection_passive_lookup_by_ids(u_int8_t *id1, u_int8_t *id2)
+{
+ struct connection_passive *conn;
+
+ for (conn = TAILQ_FIRST(&connections_passive); conn;
+ conn = TAILQ_NEXT(conn, link)) {
+ if (!conn->remote_id)
+ continue;
+
+ /*
+ * If both IDs match what we have saved, return the name.
+ * Don't bother in which order they are.
+ */
+ if ((compare_ids(id1, conn->local_id, conn->local_sz) == 0 &&
+ compare_ids(id2, conn->remote_id, conn->remote_sz) == 0) ||
+ (compare_ids(id1, conn->remote_id, conn->remote_sz) == 0 &&
+ compare_ids(id2, conn->local_id, conn->local_sz) == 0)) {
+ LOG_DBG((LOG_MISC, 60,
+ "connection_passive_lookup_by_ids: "
+ "returned \"%s\"", conn->name));
+ return conn->name;
+ }
+ }
+
+ /*
+ * In the road warrior case, we do not know the remote ID. In that
+ * case we will just match against the local ID.
+ */
+ for (conn = TAILQ_FIRST(&connections_passive); conn;
+ conn = TAILQ_NEXT(conn, link)) {
+ if (!conn->remote_id)
+ continue;
+
+ if (compare_ids(id1, conn->local_id, conn->local_sz) == 0 ||
+ compare_ids(id2, conn->local_id, conn->local_sz) == 0) {
+ LOG_DBG((LOG_MISC, 60,
+ "connection passive_lookup_by_ids: returned \"%s\""
+ " only matched local id", conn->name));
+ return conn->name;
+ }
+ }
+ LOG_DBG((LOG_MISC, 60,
+ "connection_passive_lookup_by_ids: no match"));
+ return 0;
+}
+
+/*
+ * Setup NAME to be a connection that should be up "always", i.e. if it dies,
+ * for whatever reason, it should be tried to be brought up, over and over
+ * again.
+ */
+int
+connection_setup(char *name)
+{
+ struct connection *conn = 0;
+ struct timeval now;
+
+ /* Check for trials to add duplicate connections. */
+ if (connection_lookup(name)) {
+ LOG_DBG((LOG_MISC, 10,
+ "connection_setup: cannot add \"%s\" twice", name));
+ return 0;
+ }
+ conn = calloc(1, sizeof *conn);
+ if (!conn) {
+ log_error("connection_setup: calloc (1, %lu) failed",
+ (unsigned long)sizeof *conn);
+ goto fail;
+ }
+ conn->name = strdup(name);
+ if (!conn->name) {
+ log_error("connection_setup: strdup (\"%s\") failed", name);
+ goto fail;
+ }
+ gettimeofday(&now, 0);
+ conn->ev = timer_add_event("connection_checker", connection_checker,
+ conn, &now);
+ if (!conn->ev) {
+ log_print("connection_setup: could not add timer event");
+ goto fail;
+ }
+ TAILQ_INSERT_TAIL(&connections, conn, link);
+ return 0;
+
+fail:
+ if (conn) {
+ if (conn->name)
+ free(conn->name);
+ free(conn);
+ }
+ return -1;
+}
+
+int
+connection_record_passive(char *name)
+{
+ struct connection_passive *conn;
+ char *local_id, *remote_id;
+
+ if (connection_passive_lookup_by_name(name)) {
+ LOG_DBG((LOG_MISC, 10,
+ "connection_record_passive: cannot add \"%s\" twice",
+ name));
+ return 0;
+ }
+ local_id = conf_get_str(name, "Local-ID");
+ if (!local_id) {
+ log_print("connection_record_passive: "
+ "\"Local-ID\" is missing from section [%s]", name);
+ return -1;
+ }
+ /* If the remote id lookup fails we defer it to later */
+ remote_id = conf_get_str(name, "Remote-ID");
+
+ conn = calloc(1, sizeof *conn);
+ if (!conn) {
+ log_error("connection_record_passive: calloc (1, %lu) failed",
+ (unsigned long)sizeof *conn);
+ return -1;
+ }
+ conn->name = strdup(name);
+ if (!conn->name) {
+ log_error("connection_record_passive: strdup (\"%s\") failed",
+ name);
+ goto fail;
+ }
+ /* XXX IPsec DOI-specific. */
+ conn->local_id = ipsec_build_id(local_id, &conn->local_sz);
+ if (!conn->local_id)
+ goto fail;
+
+ if (remote_id) {
+ conn->remote_id = ipsec_build_id(remote_id, &conn->remote_sz);
+ if (!conn->remote_id)
+ goto fail;
+ } else
+ conn->remote_id = 0;
+
+ TAILQ_INSERT_TAIL(&connections_passive, conn, link);
+
+ LOG_DBG((LOG_MISC, 60,
+ "connection_record_passive: passive connection \"%s\" added",
+ conn->name));
+ return 0;
+
+fail:
+ if (conn->local_id)
+ free(conn->local_id);
+ if (conn->name)
+ free(conn->name);
+ free(conn);
+ return -1;
+}
+
+/* Remove the connection named NAME. */
+void
+connection_teardown(char *name)
+{
+ struct connection *conn;
+
+ conn = connection_lookup(name);
+ if (!conn)
+ return;
+
+ TAILQ_REMOVE(&connections, conn, link);
+ timer_remove_event(conn->ev);
+ free(conn->name);
+ free(conn);
+}
+
+/* Remove the passive connection named NAME. */
+static void
+connection_passive_teardown(char *name)
+{
+ struct connection_passive *conn;
+
+ conn = connection_passive_lookup_by_name(name);
+ if (!conn)
+ return;
+
+ TAILQ_REMOVE(&connections_passive, conn, link);
+ free(conn->name);
+ free(conn->local_id);
+ free(conn->remote_id);
+ free(conn);
+}
+
+void
+connection_report(void)
+{
+ struct connection *conn;
+ struct timeval now;
+#ifdef USE_DEBUG
+ struct connection_passive *pconn;
+ struct doi *doi = doi_lookup(ISAKMP_DOI_ISAKMP);
+#endif
+
+ gettimeofday(&now, 0);
+ for (conn = TAILQ_FIRST(&connections); conn;
+ conn = TAILQ_NEXT(conn, link))
+ LOG_DBG((LOG_REPORT, 0,
+ "connection_report: connection %s next check %ld seconds",
+ (conn->name ? conn->name : "<unnamed>"),
+ conn->ev->expiration.tv_sec - now.tv_sec));
+#ifdef USE_DEBUG
+ for (pconn = TAILQ_FIRST(&connections_passive); pconn;
+ pconn = TAILQ_NEXT(pconn, link))
+ LOG_DBG((LOG_REPORT, 0,
+ "connection_report: passive connection %s %s", pconn->name,
+ doi->decode_ids("local_id: %s, remote_id: %s",
+ pconn->local_id, pconn->local_sz,
+ pconn->remote_id, pconn->remote_sz, 1)));
+#endif
+}
+
+/* Reinitialize all connections (SIGHUP handling). */
+void
+connection_reinit(void)
+{
+ struct connection *conn, *next;
+ struct connection_passive *pconn, *pnext;
+
+ LOG_DBG((LOG_MISC, 30,
+ "connection_reinit: reinitializing connection list"));
+
+ /* Remove all present connections. */
+ for (conn = TAILQ_FIRST(&connections); conn; conn = next) {
+ next = TAILQ_NEXT(conn, link);
+ connection_teardown(conn->name);
+ }
+
+ for (pconn = TAILQ_FIRST(&connections_passive); pconn; pconn = pnext) {
+ pnext = TAILQ_NEXT(pconn, link);
+ connection_passive_teardown(pconn->name);
+ }
+
+ /* Setup new connections, as the (new) config directs. */
+ connection_init();
+}
diff --git a/keyexchange/isakmpd-20041012/connection.h b/keyexchange/isakmpd-20041012/connection.h
new file mode 100644
index 0000000..41ee533
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/connection.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: connection.h,v 1.5 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: connection.h,v 1.6 1999/06/07 00:10:48 ho Exp $ */
+
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999 Hakan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * The connection module deals with connections that should always be up.
+ */
+
+#ifndef _CONNECTION_H_
+#define _CONNECTION_H_
+
+#include <sys/types.h>
+
+extern int connection_exist(char *);
+extern void connection_init(void);
+extern char *connection_passive_lookup_by_ids(u_int8_t *, u_int8_t *);
+extern void connection_reinit(void);
+extern void connection_report(void);
+extern int connection_setup(char *);
+extern int connection_record_passive(char *);
+extern void connection_teardown(char *);
+
+#endif /* _CONNECTION_H_ */
diff --git a/keyexchange/isakmpd-20041012/constants.c b/keyexchange/isakmpd-20041012/constants.c
new file mode 100644
index 0000000..ec0d0f4
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/constants.c
@@ -0,0 +1,99 @@
+/* $OpenBSD: constants.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: constants.c,v 1.7 1999/04/02 00:57:31 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "constants.h"
+
+int
+constant_value(struct constant_map *map, char *name)
+{
+ struct constant_map *entry = map;
+
+ for (entry = map; entry->name; entry++)
+ if (strcasecmp(entry->name, name) == 0)
+ return entry->value;
+ return 0;
+}
+
+char *
+constant_lookup(struct constant_map *map, int value)
+{
+ struct constant_map *entry = map;
+
+ for (entry = map; entry->name; entry++)
+ if (entry->value == value)
+ return entry->name;
+ return 0;
+}
+
+struct constant_map *
+constant_link_lookup(struct constant_map *map, int value)
+{
+ struct constant_map *entry = map;
+
+ for (entry = map; entry->name; entry++)
+ if (entry->value == value)
+ return entry->link;
+ return 0;
+}
+
+char *
+constant_name(struct constant_map *map, int value)
+{
+ static char tmp[32];/* XXX Ugly, I know. */
+ char *retval = constant_lookup(map, value);
+
+ if (!retval) {
+ snprintf(tmp, sizeof tmp, "<Unknown %d>", value);
+ return tmp;
+ }
+ return retval;
+}
+
+char *
+constant_name_maps(struct constant_map **maps, int value)
+{
+ static char tmp[32];/* XXX Ugly, I know. */
+ char *retval;
+ struct constant_map **map;
+
+ for (map = maps; *map; map++) {
+ retval = constant_lookup(*map, value);
+ if (retval)
+ return retval;
+ }
+ snprintf(tmp, sizeof tmp, "<Unknown %d>", value);
+ return tmp;
+}
diff --git a/keyexchange/isakmpd-20041012/constants.h b/keyexchange/isakmpd-20041012/constants.h
new file mode 100644
index 0000000..e3dd439
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/constants.h
@@ -0,0 +1,47 @@
+/* $OpenBSD: constants.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: constants.h,v 1.5 1998/11/20 07:17:01 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CONSTANTS_H_
+#define _CONSTANTS_H_
+
+struct constant_map {
+ int value;
+ char *name;
+ struct constant_map *link;
+};
+
+struct constant_map *constant_link_lookup(struct constant_map *, int);
+extern char *constant_lookup(struct constant_map *, int);
+extern char *constant_name(struct constant_map *, int);
+extern char *constant_name_maps(struct constant_map **, int);
+extern int constant_value(struct constant_map *, char *);
+
+#endif /* _CONSTANTS_H_ */
diff --git a/keyexchange/isakmpd-20041012/cookie.c b/keyexchange/isakmpd-20041012/cookie.c
new file mode 100644
index 0000000..ec8f826
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/cookie.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: cookie.c,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */
+/* $EOM: cookie.c,v 1.21 1999/08/05 15:00:04 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "cookie.h"
+#include "exchange.h"
+#include "hash.h"
+#include "transport.h"
+#include "util.h"
+
+#define COOKIE_SECRET_SIZE 16
+
+/*
+ * Generate an anti-clogging token (a protection against an attacker forcing
+ * us to keep state for a flood of connection requests) a.k.a. a cookie
+ * at BUF, LEN bytes long. The cookie will be generated by hashing of
+ * information found, among otherplaces, in transport T and exchange
+ * EXCHANGE.
+ */
+void
+cookie_gen(struct transport *t, struct exchange *exchange, u_int8_t *buf,
+ size_t len)
+{
+ struct hash *hash = hash_get(HASH_SHA1);
+ u_int8_t tmpsecret[COOKIE_SECRET_SIZE];
+ struct sockaddr *name;
+
+ hash->Init(hash->ctx);
+ (*t->vtbl->get_dst)(t, &name);
+ hash->Update(hash->ctx, (u_int8_t *)name, sysdep_sa_len(name));
+ (*t->vtbl->get_src)(t, &name);
+ hash->Update(hash->ctx, (u_int8_t *)name, sysdep_sa_len(name));
+ if (exchange->initiator == 0)
+ hash->Update(hash->ctx, exchange->cookies +
+ ISAKMP_HDR_ICOOKIE_OFF, ISAKMP_HDR_ICOOKIE_LEN);
+ getrandom(tmpsecret, COOKIE_SECRET_SIZE);
+ hash->Update(hash->ctx, tmpsecret, COOKIE_SECRET_SIZE);
+ hash->Final(hash->digest, hash->ctx);
+ memcpy(buf, hash->digest, len);
+}
diff --git a/keyexchange/isakmpd-20041012/cookie.h b/keyexchange/isakmpd-20041012/cookie.h
new file mode 100644
index 0000000..bfbcc01
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/cookie.h
@@ -0,0 +1,44 @@
+/* $OpenBSD: cookie.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */
+/* $EOM: cookie.h,v 1.5 1998/08/05 09:21:43 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _COOKIE_H_
+#define _COOKIE_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+struct exchange;
+struct transport;
+
+extern void cookie_gen(struct transport *, struct exchange *, u_int8_t *,
+ size_t);
+
+#endif /* _COOKIE_H_ */
diff --git a/keyexchange/isakmpd-20041012/crypto.c b/keyexchange/isakmpd-20041012/crypto.c
new file mode 100644
index 0000000..d74191e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/crypto.c
@@ -0,0 +1,413 @@
+/* $OpenBSD: crypto.c,v 1.22 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: crypto.c,v 1.32 2000/03/07 20:08:51 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "crypto.h"
+#include "log.h"
+
+enum cryptoerr des1_init(struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr des3_init(struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr blf_init(struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr cast_init(struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr aes_init(struct keystate *, u_int8_t *, u_int16_t);
+void des1_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void des1_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+void des3_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void des3_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+void blf_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void blf_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+void cast1_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void cast1_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+void aes_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void aes_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+
+struct crypto_xf transforms[] = {
+#ifdef USE_DES
+ {
+ DES_CBC, "Data Encryption Standard (CBC-Mode)", 8, 8,
+ BLOCKSIZE, 0,
+ des1_init,
+ des1_encrypt, des1_decrypt
+ },
+#endif
+#ifdef USE_TRIPLEDES
+ {
+ TRIPLEDES_CBC, "Triple-DES (CBC-Mode)", 24, 24,
+ BLOCKSIZE, 0,
+ des3_init,
+ des3_encrypt, des3_decrypt
+ },
+#endif
+#ifdef USE_BLOWFISH
+ {
+ BLOWFISH_CBC, "Blowfish (CBC-Mode)", 12, 56,
+ BLOCKSIZE, 0,
+ blf_init,
+ blf_encrypt, blf_decrypt
+ },
+#endif
+#ifdef USE_CAST
+ {
+ CAST_CBC, "CAST (CBC-Mode)", 12, 16,
+ BLOCKSIZE, 0,
+ cast_init,
+ cast1_encrypt, cast1_decrypt
+ },
+#endif
+#ifdef USE_AES
+ {
+ AES_CBC, "AES (CBC-Mode)", 16, 32,
+ AES_BLOCK_SIZE, 0,
+ aes_init,
+ aes_encrypt, aes_decrypt
+ },
+#endif
+};
+
+/* Hmm, the function prototypes for des are really dumb */
+#ifdef __OpenBSD__
+#define DC (des_cblock *)
+#else
+#define DC (void *)
+#endif
+
+enum cryptoerr
+des1_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ /* des_set_key returns -1 for parity problems, and -2 for weak keys */
+ des_set_odd_parity(DC key);
+ switch (des_set_key(DC key, ks->ks_des[0])) {
+ case -2:
+ return EWEAKKEY;
+ default:
+ return EOKAY;
+ }
+}
+
+void
+des1_encrypt(struct keystate *ks, u_int8_t *d, u_int16_t len)
+{
+ des_cbc_encrypt(DC d, DC d, len, ks->ks_des[0], DC ks->riv,
+ DES_ENCRYPT);
+}
+
+void
+des1_decrypt(struct keystate *ks, u_int8_t *d, u_int16_t len)
+{
+ des_cbc_encrypt(DC d, DC d, len, ks->ks_des[0], DC ks->riv,
+ DES_DECRYPT);
+}
+
+#ifdef USE_TRIPLEDES
+enum cryptoerr
+des3_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ des_set_odd_parity(DC key);
+ des_set_odd_parity(DC(key + 8));
+ des_set_odd_parity(DC(key + 16));
+
+ /* As of the draft Tripe-DES does not check for weak keys */
+ des_set_key(DC key, ks->ks_des[0]);
+ des_set_key(DC(key + 8), ks->ks_des[1]);
+ des_set_key(DC(key + 16), ks->ks_des[2]);
+
+ return EOKAY;
+}
+
+void
+des3_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy(iv, ks->riv, ks->xf->blocksize);
+ des_ede3_cbc_encrypt(DC data, DC data, len, ks->ks_des[0],
+ ks->ks_des[1], ks->ks_des[2], DC iv, DES_ENCRYPT);
+}
+
+void
+des3_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy(iv, ks->riv, ks->xf->blocksize);
+ des_ede3_cbc_encrypt(DC data, DC data, len, ks->ks_des[0],
+ ks->ks_des[1], ks->ks_des[2], DC iv, DES_DECRYPT);
+}
+#undef DC
+#endif /* USE_TRIPLEDES */
+
+#ifdef USE_BLOWFISH
+enum cryptoerr
+blf_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ blf_key(&ks->ks_blf, key, len);
+
+ return EOKAY;
+}
+
+void
+blf_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int8_t *iv = ks->liv;
+ u_int32_t xl, xr;
+
+ memcpy(iv, ks->riv, blocksize);
+
+ for (i = 0; i < len; data += blocksize, i += blocksize) {
+ XOR64(data, iv);
+ xl = GET_32BIT_BIG(data);
+ xr = GET_32BIT_BIG(data + 4);
+ Blowfish_encipher(&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG(data, xl);
+ SET_32BIT_BIG(data + 4, xr);
+ SET64(iv, data);
+ }
+}
+
+void
+blf_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int32_t xl, xr;
+
+ data += len - blocksize;
+ for (i = len - blocksize; i >= blocksize; data -= blocksize,
+ i -= blocksize) {
+ xl = GET_32BIT_BIG(data);
+ xr = GET_32BIT_BIG(data + 4);
+ Blowfish_decipher(&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG(data, xl);
+ SET_32BIT_BIG(data + 4, xr);
+ XOR64(data, data - blocksize);
+
+ }
+ xl = GET_32BIT_BIG(data);
+ xr = GET_32BIT_BIG(data + 4);
+ Blowfish_decipher(&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG(data, xl);
+ SET_32BIT_BIG(data + 4, xr);
+ XOR64(data, ks->riv);
+}
+#endif /* USE_BLOWFISH */
+
+#ifdef USE_CAST
+enum cryptoerr
+cast_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ cast_setkey(&ks->ks_cast, key, len);
+ return EOKAY;
+}
+
+void
+cast1_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int8_t *iv = ks->liv;
+
+ memcpy(iv, ks->riv, blocksize);
+
+ for (i = 0; i < len; data += blocksize, i += blocksize) {
+ XOR64(data, iv);
+ cast_encrypt(&ks->ks_cast, data, data);
+ SET64(iv, data);
+ }
+}
+
+void
+cast1_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+
+ data += len - blocksize;
+ for (i = len - blocksize; i >= blocksize; data -= blocksize,
+ i -= blocksize) {
+ cast_decrypt(&ks->ks_cast, data, data);
+ XOR64(data, data - blocksize);
+ }
+ cast_decrypt(&ks->ks_cast, data, data);
+ XOR64(data, ks->riv);
+}
+#endif /* USE_CAST */
+
+#ifdef USE_AES
+enum cryptoerr
+aes_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ AES_set_encrypt_key(key, len << 3, &ks->ks_aes[0]);
+ AES_set_decrypt_key(key, len << 3, &ks->ks_aes[1]);
+ return EOKAY;
+}
+
+void
+aes_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy(iv, ks->riv, ks->xf->blocksize);
+ AES_cbc_encrypt(data, data, len, &ks->ks_aes[0], iv, AES_ENCRYPT);
+}
+
+void
+aes_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy(iv, ks->riv, ks->xf->blocksize);
+ AES_cbc_encrypt(data, data, len, &ks->ks_aes[1], iv, AES_DECRYPT);
+}
+#endif /* USE_AES */
+
+struct crypto_xf *
+crypto_get(enum transform id)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof transforms / sizeof transforms[0]; i++)
+ if (id == transforms[i].id)
+ return &transforms[i];
+
+ return 0;
+}
+
+struct keystate *
+crypto_init(struct crypto_xf *xf, u_int8_t *key, u_int16_t len,
+ enum cryptoerr *err)
+{
+ struct keystate *ks;
+
+ if (len < xf->keymin || len > xf->keymax) {
+ LOG_DBG((LOG_CRYPTO, 10, "crypto_init: invalid key length %d",
+ len));
+ *err = EKEYLEN;
+ return 0;
+ }
+ ks = calloc(1, sizeof *ks);
+ if (!ks) {
+ log_error("crypto_init: calloc (1, %lu) failed",
+ (unsigned long)sizeof *ks);
+ *err = ENOCRYPTO;
+ return 0;
+ }
+ ks->xf = xf;
+
+ /* Setup the IV. */
+ ks->riv = ks->iv;
+ ks->liv = ks->iv2;
+
+ LOG_DBG_BUF((LOG_CRYPTO, 40, "crypto_init: key", key, len));
+
+ *err = xf->init(ks, key, len);
+ if (*err != EOKAY) {
+ LOG_DBG((LOG_CRYPTO, 30, "crypto_init: weak key found for %s",
+ xf->name));
+ free(ks);
+ return 0;
+ }
+ return ks;
+}
+
+void
+crypto_update_iv(struct keystate *ks)
+{
+ u_int8_t *tmp;
+
+ tmp = ks->riv;
+ ks->riv = ks->liv;
+ ks->liv = tmp;
+
+ LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_update_iv: updated IV", ks->riv,
+ ks->xf->blocksize));
+}
+
+void
+crypto_init_iv(struct keystate *ks, u_int8_t *buf, size_t len)
+{
+ memcpy(ks->riv, buf, len);
+
+ LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_init_iv: initialized IV", ks->riv,
+ len));
+}
+
+void
+crypto_encrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len)
+{
+ LOG_DBG_BUF((LOG_CRYPTO, 10, "crypto_encrypt: before encryption", buf,
+ len));
+ ks->xf->encrypt(ks, buf, len);
+ memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize);
+ LOG_DBG_BUF((LOG_CRYPTO, 30, "crypto_encrypt: after encryption", buf,
+ len));
+}
+
+void
+crypto_decrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len)
+{
+ LOG_DBG_BUF((LOG_CRYPTO, 10, "crypto_decrypt: before decryption", buf,
+ len));
+ /*
+ * XXX There is controversy about the correctness of updating the IV
+ * like this.
+ */
+ memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize);
+ ks->xf->decrypt(ks, buf, len);
+ LOG_DBG_BUF((LOG_CRYPTO, 30, "crypto_decrypt: after decryption", buf,
+ len));
+}
+
+/* Make a copy of the keystate pointed to by OKS. */
+struct keystate *
+crypto_clone_keystate(struct keystate *oks)
+{
+ struct keystate *ks;
+
+ ks = malloc(sizeof *ks);
+ if (!ks) {
+ log_error("crypto_clone_keystate: malloc (%lu) failed",
+ (unsigned long)sizeof *ks);
+ return 0;
+ }
+ memcpy(ks, oks, sizeof *ks);
+ if (oks->riv == oks->iv) {
+ ks->riv = ks->iv;
+ ks->liv = ks->iv2;
+ } else {
+ ks->riv = ks->iv2;
+ ks->liv = ks->iv;
+ }
+ return ks;
+}
diff --git a/keyexchange/isakmpd-20041012/crypto.h b/keyexchange/isakmpd-20041012/crypto.h
new file mode 100644
index 0000000..1095c7e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/crypto.h
@@ -0,0 +1,175 @@
+/* $OpenBSD: crypto.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */
+/* $EOM: crypto.h,v 1.12 2000/10/15 21:56:41 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CRYPTO_H_
+#define _CRYPTO_H_
+
+#if defined (__APPLE__)
+
+#include <openssl/des.h>
+#ifdef USE_BLOWFISH
+#include <openssl/blowfish.h>
+#endif
+#ifdef USE_CAST
+#include <openssl/cast.h>
+#endif
+
+#else
+
+#include <des.h>
+#ifdef USE_BLOWFISH
+#include <blf.h>
+#endif
+#ifdef USE_CAST
+#include <cast.h>
+#endif
+
+#endif /* __APPLE__ */
+
+#ifdef USE_AES
+#include <openssl/aes.h>
+#endif
+
+#define USE_32BIT
+#if defined (USE_64BIT)
+
+#define XOR64(x,y) *(u_int64_t *)(x) ^= *(u_int64_t *)(y);
+#define SET64(x,y) *(u_int64_t *)(x) = *(u_int64_t *)(y);
+
+#elif defined (USE_32BIT)
+
+#define XOR64(x,y) *(u_int32_t *)(x) ^= *(u_int32_t *)(y); \
+ *(u_int32_t *)((u_int8_t *)(x) + 4) ^= *(u_int32_t *)((u_int8_t *)(y) + 4);
+#define SET64(x,y) *(u_int32_t *)(x) = *(u_int32_t *)(y); \
+ *(u_int32_t *)((u_int8_t *)(x) + 4) = *(u_int32_t *)((u_int8_t *)(y) + 4);
+
+#else
+
+#define XOR8(x,y,i) (x)[i] ^= (y)[i];
+#define XOR64(x,y) XOR8(x,y,0); XOR8(x,y,1); XOR8(x,y,2); XOR8(x,y,3); \
+ XOR8(x,y,4); XOR8(x,y,5); XOR8(x,y,6); XOR8(x,y,7);
+#define SET8(x,y,i) (x)[i] = (y)[i];
+#define SET64(x,y) SET8(x,y,0); SET8(x,y,1); SET8(x,y,2); SET8(x,y,3); \
+ SET8(x,y,4); SET8(x,y,5); SET8(x,y,6); SET8(x,y,7);
+
+#endif /* USE_64BIT */
+
+#define SET_32BIT_BIG(x,y) (x)[3]= (y); (x)[2]= (y) >> 8; \
+ (x)[1] = (y) >> 16; (x)[0]= (y) >> 24;
+#define GET_32BIT_BIG(x) (u_int32_t)(x)[3] | ((u_int32_t)(x)[2] << 8) | \
+ ((u_int32_t)(x)[1] << 16)| ((u_int32_t)(x)[0] << 24);
+
+/*
+ * This is standard for all block ciphers we use at the moment.
+ * Keep MAXBLK uptodate.
+ */
+#define BLOCKSIZE 8
+
+#ifdef USE_AES
+#define MAXBLK AES_BLOCK_SIZE
+#else
+#define MAXBLK BLOCKSIZE
+#endif
+
+struct keystate {
+ struct crypto_xf *xf; /* Back pointer */
+ u_int16_t ebytes; /* Number of encrypted bytes */
+ u_int16_t dbytes; /* Number of decrypted bytes */
+ time_t life; /* Creation time */
+ u_int8_t iv[MAXBLK]; /* Next IV to use */
+ u_int8_t iv2[MAXBLK];
+ u_int8_t *riv, *liv;
+ union {
+ des_key_schedule desks[3];
+#ifdef USE_BLOWFISH
+ blf_ctx blfks;
+#endif
+#ifdef USE_CAST
+ cast_key castks;
+#endif
+#ifdef USE_AES
+ AES_KEY aesks[2];
+#endif
+ } keydata;
+};
+
+#define ks_des keydata.desks
+#define ks_blf keydata.blfks
+#define ks_cast keydata.castks
+#define ks_aes keydata.aesks
+
+/*
+ * Information about the cryptotransform.
+ *
+ * XXX - In regards to the IV (Initialization Vector) the drafts are
+ * completly fucked up and specify a MUST as how it is derived, so
+ * we also have to provide for that. I just don't know where.
+ * Furthermore is this enum needed at all? It seems to be Oakley IDs
+ * only anyhow, and we already have defines for that in ipsec_doi.h.
+ */
+enum transform {
+ DES_CBC = 1, /* This is a MUST */
+ IDEA_CBC = 2, /* Licensed, DONT use */
+ BLOWFISH_CBC = 3,
+ RC5_R16_B64_CBC = 4, /* Licensed, DONT use */
+ TRIPLEDES_CBC = 5, /* This is a SHOULD */
+ CAST_CBC = 6,
+ AES_CBC = 7
+};
+
+enum cryptoerr {
+ EOKAY, /* No error */
+ ENOCRYPTO, /* A none crypto related error, see errno */
+ EWEAKKEY, /* A weak key was found in key setup */
+ EKEYLEN /* The key length was invalid for the cipher */
+};
+
+struct crypto_xf {
+ enum transform id; /* Oakley ID */
+ char *name; /* Transform Name */
+ u_int16_t keymin, keymax; /* Possible Keying Bytes */
+ u_int16_t blocksize; /* Need to keep IV in the state */
+ struct keystate *state; /* Key information, can also be passed sep. */
+ enum cryptoerr (*init)(struct keystate *, u_int8_t *, u_int16_t);
+ void (*encrypt)(struct keystate *, u_int8_t *, u_int16_t);
+ void (*decrypt)(struct keystate *, u_int8_t *, u_int16_t);
+};
+
+extern struct keystate *crypto_clone_keystate(struct keystate *);
+extern void crypto_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+extern void crypto_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+extern struct crypto_xf *crypto_get(enum transform);
+extern struct keystate *crypto_init(struct crypto_xf *, u_int8_t *, u_int16_t,
+ enum cryptoerr *);
+extern void crypto_init_iv(struct keystate *, u_int8_t *, size_t);
+extern void crypto_update_iv(struct keystate *);
+
+#endif /* _CRYPTO_H_ */
diff --git a/keyexchange/isakmpd-20041012/debian/ChangeLog b/keyexchange/isakmpd-20041012/debian/ChangeLog
new file mode 100644
index 0000000..bae602d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/ChangeLog
@@ -0,0 +1,1668 @@
+End of changelog debian package isakmpd.20041012-1
+--------------------------------------------------
+
+2004-10-08 17:18 hshoexer
+
+ * sysdep/common/libsysdep/arc4random.c: pull in some changes from
+ libc arc4random (only relevant for non-OpenBSD systems): ansify,
+ discard first 256 output bytes, make key schedule more arc4
+ stream ciper like.
+
+ ok djm ho
+
+2004-10-01 06:08 jsg
+
+ * monitor_fdpass.c: add some missing $, ok djm@ 'That looks fine to
+ me' millert@
+
+2004-09-24 15:31 ho
+
+ * udp_encap.c: Don't process NAT-T keepalives. Noted by Kamel
+ Messaoudi. hshoexer@ ok
+
+2004-09-20 23:36 hshoexer
+
+ * virtual.c: compile cleanly with -Wsign-compare ok ho
+
+2004-09-20 23:35 hshoexer
+
+ * monitor_fdpass.c: Remove __func__ ok ho deraadt
+
+2004-09-17 16:54 hshoexer
+
+ * isakmpd.c: avoid signal race.
+
+ ok ho@ otto@
+
+2004-09-17 15:53 ho
+
+ * exchange.c, ike_quick_mode.c, ipsec.c, key.c, pf_key_v2.c:
+ Missing #ifdefs.
+
+2004-09-17 15:46 ho
+
+ * init.c: #include <stdlib.h> for srandom().
+
+2004-09-17 15:45 ho
+
+ * message.c: Permit next payload type NAT-OA. Noted by Kamel
+ Messaoudi.
+
+2004-08-23 13:53 ho
+
+ * exchange.c: We need to set sa->initiator before checking if the
+ newly created SA replaces an old one, or the id_i/id_r check will
+ mismatch. Previous behaviour was mostly harmless, but wasted some
+ resources (until normal SA expiration). hshoexer@ "haven't tried,
+ but think it's ok"
+
+2004-08-23 13:16 ho
+
+ * Makefile: Default enable DPD (Dead Peer Detection) support.
+ hshoexer@ ok
+
+2004-08-23 13:13 ho
+
+ * exchange.h: Indent nit.
+
+2004-08-17 16:48 hshoexer
+
+ * message.c: check for msg->isakmpg_sa being NULL before
+ referencing ok ho@
+
+2004-08-14 15:29 hshoexer
+
+ * ike_quick_mode.c: When using -K (keynote disabled), check peers'
+ proposal against isakmpd.conf.
+
+ ok ho@ henning@
+
+2004-08-13 04:51 djm
+
+ * monitor_fdpass.c: extra check for no message case; ok markus,
+ deraadt, hshoexer, henning
+
+2004-08-12 13:21 hshoexer
+
+ * monitor.c: Fix compiler warning on alpha. Noted by and ok ho@
+
+2004-08-12 13:08 ho
+
+ * pf_key_v2.c: Avoid memleak on error (Linux/KAME). Found by
+ Benjamin Pineau.
+
+2004-08-10 21:21 deraadt
+
+ * virtual.c, x509.c: spacing
+
+2004-08-10 17:59 ho
+
+ * dpd.c, dpd.h, exchange.c, ipsec.c, isakmp_num.cst,
+ isakmpd.conf.5, message.c, message.h, pf_key_v2.c, pf_key_v2.h,
+ sa.c, sa.h, sysdep.h, udp_encap.c, sysdep/bsdi/sysdep.c,
+ sysdep/darwin/sysdep.c, sysdep/freebsd/sysdep.c,
+ sysdep/freeswan/sysdep.c, sysdep/linux/sysdep.c,
+ sysdep/netbsd/sysdep.c, sysdep/openbsd/sysdep.c: Better
+ implementation of the Dead Peer Detection protocol, RFC 3706.
+ hshoexer@ ok.
+
+2004-08-10 11:49 ho
+
+ * sysdep/linux/GNUmakefile.sysdep: Linux has AES (and DES). From
+ Benjamin Pineau.
+
+2004-08-10 11:47 ho
+
+ * sysdep/common/libsysdep/arc4random.c: If opening /dev/arandom
+ fails, try /dev/random. Suggested by Benjamin Pineau.
+
+2004-08-08 21:11 deraadt
+
+ * GNUmakefile, conf.c, dpd.c, exchange.c, ike_auth.c,
+ ike_phase_1.c, ike_quick_mode.c, ipsec.c, isakmp_cfg.c, log.c,
+ message.c, monitor.c, nat_traversal.c, pf_key_v2.c, policy.c,
+ sa.c, sysdep.h, transport.c, udp.c, udp_encap.c, ui.c, util.c,
+ virtual.c, x509.c: spacing
+
+2004-08-03 12:54 ho
+
+ * nat_traversal.c, transport.c, udp.c, udp.h, udp_encap.c,
+ virtual.c: Rewrite the transport reference count code to avoid
+ leaks. hshoexer@ ok.
+
+2004-08-02 17:48 hshoexer
+
+ * sa.c: Do not expire unestablished phase 2 SAs on SIGHUP.
+
+ ok ho@
+
+2004-08-02 17:30 ho
+
+ * GNUmakefile: Missed to add virtual.c here. Noted by Benjamin
+ Pineau.
+
+2004-07-30 12:45 ho
+
+ * Makefile, sysdep.h, util.c: Style.
+
+2004-07-29 22:02 ho
+
+ * conf.c: Less noise while debugging.
+
+2004-07-29 10:54 ho
+
+ * ike_aggressive.c, ike_phase_1.c, nat_traversal.c: Repair NAT-T
+ using Aggressive mode, NAT-D checks were in the wrong place.
+ Noted by Yvan VANHULLEBUS.
+
+2004-07-09 18:06 deraadt
+
+ * doi.c, exchange.c: ansi
+
+2004-07-08 21:53 hshoexer
+
+ * virtual.c: free() and close() in error path.
+
+ ok ho@
+
+2004-07-08 12:37 jmc
+
+ * isakmpd.8, isakmpd.conf.5: typo, and line adjustment;
+
+2004-07-08 00:25 hshoexer
+
+ * isakmpd.8, isakmpd.conf.5: document -a/-K and
+ "Acquire-Only"/"Use-Keynote".
+
+ ok markus@ henning@ ho@ english polish and mdoc help and ok jmc@
+
+2004-07-07 11:16 hshoexer
+
+ * message.c: plug memleak when receiving an
+ INVALID_HASH_INFORMATION notify. Found by Patrick Latifi,
+ thanks!
+
+ ok ho@
+
+2004-07-07 11:13 hshoexer
+
+ * udp_encap.c: compile cleanly with -Wsign-compare; while around,
+ kill a space
+
+ ok ho@
+
+2004-07-05 19:33 pvalchev
+
+ * ike_phase_1.c: %lu and cast to unsigned long to print a size_t;
+ ok ho
+
+2004-06-30 12:07 hshoexer
+
+ * nat_traversal.c: Compile cleanly with gcc3.3.2.
+
+ ok ho@
+
+2004-06-26 13:32 jmc
+
+ * isakmpd.conf.5: new sentence, new line;
+
+2004-06-26 08:07 hshoexer
+
+ * monitor.c, monitor.h, pf_key_v2.c, pf_key_v2.h,
+ sysdep/openbsd/sysdep.c: Narrow down privsep interface. Move
+ pf_key_v2_open() to monitor.
+
+ Work in progress.
+
+ ok ho@
+
+2004-06-26 05:40 mcbride
+
+ * sysdep/: bsdi/Makefile.sysdep, darwin/GNUmakefile.sysdep,
+ darwin/Makefile.sysdep, freebsd/GNUmakefile.sysdep,
+ freebsd/Makefile.sysdep, linux/GNUmakefile.sysdep,
+ netbsd/GNUmakefile.sysdep, netbsd/Makefile.sysdep,
+ openbsd/GNUmakefile.sysdep, openbsd/Makefile.sysdep: Remove
+ -DHAVE_GETNAMEINFO frome makefiles.
+
+ Pointed out by ho@
+
+2004-06-25 22:25 hshoexer
+
+ * conf.c, conf.h, ike_quick_mode.c, isakmpd.c, policy.c, policy.h:
+ Keynote policy checking can now be disabled by "-K" switch and
+ config tag "Use-Keynote". Default is to use keynote.
+
+ ok henning@ ho@
+
+2004-06-25 21:42 mcbride
+
+ * udp.c, util.c: Remove HAVE_GETNAMEINFO alternate code. Compiled
+ binary is unchanged.
+
+ ok msf@ hshoexer@ itojun@ ho@
+
+2004-06-25 02:58 hshoexer
+
+ * init.c, log.c, monitor.c, monitor.h, ui.c: Narrow down privsep
+ interface. Remove ui_init to monitor. So we can get rid of
+ monitor_mkfifo.
+
+ Work in progress.
+
+ ok ho@
+
+2004-06-24 19:02 hshoexer
+
+ * monitor.c: Remove some unused code. Fix handling of sigchild.
+ Now it's possible to sigstop/sigcont isakmpd correclty.
+
+ ok ho@
+
+2004-06-24 17:58 hshoexer
+
+ * policy.c: Also handle keys from x509-certificates embedded in
+ keynote credentials.
+
+ with msf@ ok ho@
+
+2004-06-24 01:36 ho
+
+ * pf_key_v2.c: Print corrent prefix. Found and tested by alex at
+ vbone.net.
+
+2004-06-23 05:01 hshoexer
+
+ * ike_auth.c, util.c, util.h: Avoid stat before open. Do open and
+ fstat instead. Remove check_file_secrecy() as it is obsoleted be
+ check_file_secrecy_fd().
+
+ ok ho@
+
+2004-06-23 03:17 ho
+
+ * Makefile, sysdep.h, util.c: Make compiling with Boehm's gc
+ possible again.
+
+2004-06-23 02:56 ho
+
+ * ike_phase_1.c: Support IPV{4,6}_ADDR_SUBNET IDs in Phase 1, just
+ like the man page says we do. Noted and tested by alex at
+ vbone.net. Also avoid a potential SEGV here. hshoexer@ok
+
+2004-06-23 02:55 hshoexer
+
+ * ipsec.c, isakmpd.c: Add commandline switch -a / config tag
+ "Acquire-Only" to tell isakmpd to not touch flows.
+
+ initial work by markus ok markus@ ho@ henning@
+
+2004-06-22 20:22 hshoexer
+
+ * ike_auth.c: kn_get_string() may return NULL on failure. Handle
+ this corrctly.
+
+ with msf@, ok ho@ markus@
+
+2004-06-22 05:44 ho
+
+ * virtual.c: The NAT-T drafts suggest we should drop incoming
+ messages arriving on the old port (500) after we've switched to
+ the new one.
+
+2004-06-22 01:42 ho
+
+ * isakmpd.conf.5: Describe the [Default]:NAT-T-Keepalive
+ configuration parameter.
+
+2004-06-22 01:28 ho
+
+ * Makefile: Enable NAT-T support.
+
+2004-06-22 01:27 ho
+
+ * ipsec.c, nat_traversal.c, nat_traversal.h, sa.c, sa.h,
+ udp_encap.c: Implement NAT-T keepalive messages.
+
+2004-06-21 20:41 ho
+
+ * pf_key_v2.c: udpencap_port should be taken from dst transport
+
+2004-06-21 20:40 ho
+
+ * virtual.c: When switching from main to encap transport, copy dst
+ port if translated (NAT).
+
+2004-06-21 20:34 ho
+
+ * monitor.c: Strip away umask bits in monitor_fopen(). hshoexer@
+ ok.
+
+2004-06-21 20:29 ho
+
+ * ipsec.c: style nit
+
+2004-06-21 19:02 markus
+
+ * features/nat_traversal: undo double-patch; Dries Schellekens
+
+2004-06-21 18:37 ho
+
+ * log.c: Don't write too much IKE data in packet capture
+
+2004-06-21 18:01 ho
+
+ * log.c, message.c: Packet capture should add the ESP-marker when
+ NAT-T is active.
+
+2004-06-21 17:15 ho
+
+ * pf_key_v2.c: Tell the kernel to enable ESP-in-UDP encapsulation
+ when we have SAs negotiated with NAT-T.
+
+2004-06-21 15:09 ho
+
+ * exchange.c, sa.h, transport.c, udp.c, udp_encap.c, virtual.c:
+ Port floating (500->4500) for p1 and p2 exchanges.
+
+2004-06-20 19:44 ho
+
+ * message.c: message_parse_payloads should accept payloads in the
+ private range. While here, also cleanup some messages.
+
+2004-06-20 19:17 ho
+
+ * dpd.c, exchange.c, ike_auth.c, ike_phase_1.c, ike_quick_mode.c,
+ init.c, ipsec.c, isakmp_cfg.c, isakmp_doi.c, message.c,
+ message.h, nat_traversal.c: Make the payload array in struct
+ message dynamic, since we need to handle payloads in the private
+ range, such as the pre-RFC NAT-D/NAT-OA. Replace
+ TAILQ_FIRST(&msg->payload[i]) instances with function calls.
+
+2004-06-20 17:24 ho
+
+ * Makefile, exchange.h, ike_phase_1.c, init.c, ipsec.c, isakmp.h,
+ isakmp_fld.fld, message.c, nat_traversal.c, nat_traversal.h,
+ policy.c, transport.c, transport.h, udp.c, udp.h, udp_encap.c,
+ udp_encap.h, util.c, util.h, virtual.c, virtual.h,
+ features/nat_traversal: NAT-Traversal for isakmpd. Work in
+ progress... hshoexer@ ok.
+
+2004-06-20 17:20 ho
+
+ * dpd.c, dpd.h, exchange.c, isakmp_num.cst, sa.h, features/dpd: A
+ start towards Dead Peer Detection (DPD) support, as specified in
+ RFC 3706
+
+2004-06-20 17:11 ho
+
+ * message.c: Some vendors send the last Aggressive Mode message
+ unencrypted, which we should accept. Problem noted by alex at
+ vbone.net. hshoexer@ ok.
+
+2004-06-20 17:03 ho
+
+ * isakmpd.c, monitor.c, monitor.h: To make debugging the
+ unprivileged child process easier, make 'isakmpd -dd' pause just
+ after privsep; print the PIDs and wait for SIGCONT. hshoexer@ ok
+
+2004-06-17 21:39 hshoexer
+
+ * ipsec.c: Yet another bunch of memleask found and fixed by Patrick
+ Latifi. Thanks!
+
+ ok ho@
+
+2004-06-17 21:36 hshoexer
+
+ * udp.c: Plug a memleak. Found and fixed (and some cleanup) by
+ Patrick Latifi. Thanks!
+
+ ok ho@
+
+2004-06-17 21:32 hshoexer
+
+ * x509.c: Evaluate result of X509_verify_cert() more carefully.
+
+ ok cloder@
+
+2004-06-16 17:08 hshoexer
+
+ * util.c: Fix wrong pointer dereference and plug memleak. Found
+ and patch by Patrick Latifi. Thanks!
+
+ ok ho@
+
+2004-06-16 17:05 hshoexer
+
+ * ipsec.c: fix ipv6-address and ipv6-address-mask mixup. Found by
+ Patrick Latifi. Thanks!
+
+ ok ho@
+
+2004-06-15 17:53 hshoexer
+
+ * ike_quick_mode.c, isakmp_cfg.c: also use MSG_AUTHENTICATED flag.
+
+ ok ho@
+
+2004-06-14 15:53 hshoexer
+
+ * conf.c, ike_auth.c, x509.c: avoid stat before open
+
+ ok ho@
+
+2004-06-14 12:04 hshoexer
+
+ * message.c: added a missing message_free().
+
+ ok ho@
+
+2004-06-14 11:55 ho
+
+ * cert.c, conf.c, connection.c, crypto.c, dnssec.c, exchange.c,
+ field.c, hash.c, if.c, ike_auth.c, ike_main_mode.c,
+ ike_phase_1.c, ike_quick_mode.c, ipsec.c, isakmp_cfg.c,
+ isakmp_doi.c, isakmpd.c, key.c, log.c, math_2n.c, math_group.c,
+ message.c, monitor.c, pf_key_v2.c, policy.c, timer.c,
+ transport.c, udp.c, util.c, x509.c: KNF, style, 80c, etc.
+ hshoexer@ ok
+
+2004-06-11 12:17 brad
+
+ * message.c: typo in comment
+
+2004-06-11 05:08 brad
+
+ * ike_phase_1.c, ike_quick_mode.c, ipsec.c, message.c, message.h:
+ MFC: Fix by hshoexer@
+
+ Mark authenticated messages explicitly. Better check for
+ authentication before deleteing SAs.
+
+ This fix is needed to solve the problems reported by Thomas
+ Walpuski, previous diff was not sufficient. Pointed out by
+ Thomas. Thanks!
+
+2004-06-11 04:34 brad
+
+ * ike_phase_1.c, ike_quick_mode.c, ipsec.c, message.c, message.h:
+ MFC: Fix by hshoexer@
+
+ Mark authenticated messages explicitly. Better check for
+ authentication before deleteing SAs.
+
+ This fix is needed to solve the problems reported by Thomas
+ Walpuski, previous diff was not sufficient. Pointed out by
+ Thomas. Thanks!
+
+2004-06-10 14:54 hshoexer
+
+ * ike_phase_1.c, ike_quick_mode.c, ipsec.c, message.c, message.h:
+ Mark authenticated messages explicitly. Better check for
+ authentication before deleteing SAs.
+
+ This fix is needed to solve the problems reported by Thomas
+ Walpuski, previous diff was not sufficient. Pointed out by
+ Thomas. Thanks!
+
+ ok ho@ niklas@, testing and spellcheck by todd@ msf@
+
+2004-06-09 23:15 brad
+
+ * message.c: MFC: Fix by hshoexer@
+
+ only accept DELETEs during an authenticated INFORMATIONAL
+ exchange. Fix for recent problem disclosed by Thomas Walpuski.
+
+2004-06-09 22:48 brad
+
+ * message.c: MFC: Fix by hshoexer@
+
+ only accept DELETEs during an authenticated INFORMATIONAL
+ exchange. Fix for recent problem disclosed by Thomas Walpuski.
+
+2004-06-09 16:02 ho
+
+ * conf.c, exchange.c, ike_phase_1.c, ike_quick_mode.c, ipsec.c,
+ isakmp_cfg.c, message.c, pf_key_v2.c, transport.c, udp.c: Style
+ nits. hshoexer@ ok
+
+2004-06-09 14:59 hshoexer
+
+ * message.c: only accept DELETEs during an authenticated
+ INFORMATIONAL exchange. Fix for recent problem disclosed by
+ Thomas Walpuski.
+
+ ok ho@
+
+2004-06-06 15:05 ho
+
+ * ike_phase_1.c: Style (KNF, 80c). No binary change.
+
+2004-06-02 18:19 hshoexer
+
+ * ike_auth.c, x509.c: remove unused BIO-functions.
+
+ ok markus@ ho@
+
+2004-05-27 00:17 hshoexer
+
+ * ike_auth.c: do not leak fd on error path.
+
+ ok ho@
+
+2004-05-24 16:54 hshoexer
+
+ * util.c: Use correct function names in log messages. Kill some
+ spaces.
+
+ ok deraadt@ ho@
+
+2004-05-23 20:17 hshoexer
+
+ * field.c, field.h, hash.c, if.c, ike_aggressive.c,
+ ike_aggressive.h, ike_auth.c, ike_main_mode.c, ike_main_mode.h,
+ ipsec.c, ipsec.h, isakmp_cfg.c, isakmp_cfg.h, isakmp_doi.c,
+ isakmpd.c, key.c, log.c, log.h, math_2n.c, math_ec2n.c,
+ math_ec2n.h, math_group.c, message.c, message.h, monitor.c,
+ monitor_fdpass.c, pf_key_v2.h, policy.c, prf.c, sa.c, sa.h,
+ timer.c, timer.h, udp.c, ui.c, util.c, x509.c, x509.h: More KNF.
+ Mainly spaces and line-wraps, no binary change.
+
+ ok ho@
+
+2004-05-23 18:14 deraadt
+
+ * if.c, udp.c: remove excessive monitor_ prefixes
+
+2004-05-23 18:14 deraadt
+
+ * policy.c, util.c, util.h: stat before open is flawed
+
+2004-05-23 18:13 deraadt
+
+ * key.c: greater care with arguments
+
+2004-05-19 16:30 ho
+
+ * ipsec.c, isakmpd.c: Permit symbolic protocol and service names,
+ such as "Protocol= tcp", in the <IPsec-ID> sections. hshoexer@ ok
+
+2004-05-14 10:42 hshoexer
+
+ * attribute.c, attribute.h, cert.c, cert.h, conf.c, conf.h,
+ connection.c, cookie.c, cookie.h, crypto.c, crypto.h, dh.h,
+ dnssec.c, dnssec.h, doi.c, doi.h: Some more KNF, no binary
+ change.
+
+ ok ho@
+
+2004-05-13 08:56 ho
+
+ * connection.c, isakmpd.8, sa.c, sa.h, ui.c, ui.h: Extensions to
+ the FIFO interface: "C get [section]:tag" fetches a configuration
+ value. "C add [section]:tag=value" adds 'value' to a list,
+ typically for the [Phase 2]:Connections tag. FIFO "S" command
+ destination file changed. Various KNF cleanups. hshoexer@ ok.
+
+2004-05-10 20:34 deraadt
+
+ * monitor.c: 64bit gcc saw missing cast
+
+2004-05-06 12:40 ho
+
+ * exchange.c: KNF cleanup. hshoexer@ ok
+
+2004-05-03 23:23 hshoexer
+
+ * exchange.c, exchange.h: KNF. ok ho@
+
+2004-04-30 00:36 hshoexer
+
+ * message.c: Better checking of minimum payload lengths. Drop out
+ safely when an unknown payload type is encountered. While
+ around, do some KNF.
+
+ ok ho@
+
+2004-04-28 22:20 hshoexer
+
+ * ike_quick_mode.c, policy.c, policy.h: remove unused variable and
+ shorten names of two other. Removed some spaces while around.
+
+ ok ho@ markus@
+
+2004-04-28 16:40 ho
+
+ * ipsec_num.cst, isakmp_num.cst: Reserve some payload numbers for
+ RFC 3547 and the earlier NAT-T drafts. hshoexer@ ok.
+
+2004-04-23 16:15 ho
+
+ * conf.c, conf.h: Make sure KEY_LENGTH attribute is present when
+ checking AES proposals, required when acting as responder to
+ SafeNet peers. Also make conf_load_defaults() readable again
+ (KNF). hshoexer@ ok.
+
+2004-04-15 22:20 deraadt
+
+ * conf.c: more knf; ok hshoexer
+
+2004-04-15 20:53 deraadt
+
+ * conf.c: knf
+
+2004-04-15 20:39 deraadt
+
+ * app.c, app.h, attribute.c, attribute.h, cert.c, cert.h, conf.c,
+ conf.h, connection.c, connection.h, constants.c, constants.h,
+ cookie.c, cookie.h, crypto.c, crypto.h, dh.c, dh.h, dnssec.c,
+ dnssec.h, doi.c, doi.h, exchange.h, field.c, field.h,
+ genconstants.sh, genfields.sh, gmp_util.c, gmp_util.h, hash.c,
+ hash.h, if.c, if.h, ike_aggressive.c, ike_aggressive.h,
+ ike_auth.c, ike_auth.h, ike_main_mode.c, ike_main_mode.h,
+ ike_phase_1.c, ike_phase_1.h, ike_quick_mode.c, ike_quick_mode.h,
+ init.c, init.h, ipsec.c, ipsec.h, ipsec_doi.h, isakmp.h,
+ isakmp_cfg.c, isakmp_cfg.h, isakmp_doi.c, isakmp_doi.h,
+ isakmpd.c, key.c, key.h, libcrypto.c, libcrypto.h, log.c, log.h,
+ math_2n.c, math_2n.h, math_ec2n.c, math_ec2n.h, math_group.c,
+ math_group.h, math_mp.h, message.c, message.h, monitor.c,
+ monitor.h, monitor_fdpass.c, pf_key_v2.c, pf_key_v2.h, policy.c,
+ policy.h, prf.c, prf.h, sa.c, sa.h, sysdep.h, timer.c, timer.h,
+ transport.c, transport.h, udp.c, udp.h, ui.c, ui.h, util.c,
+ util.h, x509.c, x509.h, sysdep/openbsd/keynote_compat.c,
+ sysdep/openbsd/sysdep.c: partial move to KNF. More to come.
+ This has happened because there are a raft of source code
+ auditors who are willing to help improve this code only if this
+ is done, and hey, isakmpd does need our standard auditing
+ process. ok ho hshoexer
+
+2004-04-15 02:27 deraadt
+
+ * isakmpd.8: spaces
+
+2004-04-13 23:48 hshoexer
+
+ * if.c: Add missing #include. Found by Stefan Paletta.
+
+ ok henning@ ho@
+
+2004-04-08 18:08 henning
+
+ * sysdep/linux/sys/queue.h: swap the last two parameters to
+ TAILQ_FOREACH_REVERSE. matches what FreeBSD and NetBSD do. ok
+ millert@ mcbride@ markus@ ho@, checked to not affect ports by
+ naddy@
+
+2004-04-08 12:05 hshoexer
+
+ * init.c, isakmpd.c: Set timezone before privsep, child uses now
+ correct timezone. Noticed by david@
+
+ ok ho@ david@
+
+2004-04-08 00:45 ho
+
+ * conf.h, exchange.h, ike_auth.c, ike_phase_1.c, ike_quick_mode.c,
+ ipsec.c, log.c, math_2n.c, math_group.c, math_group.h, message.c,
+ monitor.c, pf_key_v2.c, policy.c, sa.c, udp.c, ui.c, util.c,
+ x509.c, regress/crypto/cryptotest.c: -Wsign-compare nits.
+ hshoexer@ ok.
+
+2004-04-08 00:45 ho
+
+ * key.c: Reset *data in case of unknown key types
+
+2004-04-08 00:43 ho
+
+ * Makefile: -Wmissing-declarations
+
+2004-04-07 22:04 ho
+
+ * sa.c: More careful when walking LIST queues. hshoexer@, david@
+ ok.
+
+2004-03-31 12:54 ho
+
+ * cert.c, crypto.c, exchange.c, hash.c, ike_auth.c: -Wsign-compare
+ nits. hshoexer@ ok.
+
+2004-03-31 12:53 ho
+
+ * monitor.c: Use sysdep_sa_len() instead of sa->sa_len, also
+ correct a log_fatal() message. hshoexer@ ok.
+
+2004-03-31 12:47 ho
+
+ * isakmpd.c, sysdep/openbsd/Makefile.sysdep: Don't assume
+ closefrom(2) exists everywhere. hshoexer@, markus@ ok.
+
+2004-03-29 19:07 deraadt
+
+ * monitor.c: use malloc (oops)
+
+2004-03-29 18:32 deraadt
+
+ * monitor.c: wrong FD_ZERO(); from ho, hshoexer, markus
+
+2004-03-29 18:32 deraadt
+
+ * udp.c: memory mishandling; from ho
+
+2004-03-24 17:44 hshoexer
+
+ * isakmpd.8: Add some notes about privsep to manpage.
+
+ ok ho@ jmc@ deraadt@
+
+2004-03-23 19:20 hshoexer
+
+ * monitor.c: Remove erroneous null termination.
+
+ ok ho@ deraadt@
+
+2004-03-19 15:04 hshoexer
+
+ * Makefile, conf.c, conf.h, if.c, ike_auth.c, isakmpd.c, log.c,
+ monitor.c, monitor.h, policy.c, sa.c, udp.c, ui.c, x509.c: Add
+ missing bits to make already present privsep code work. Enable
+ privsep.
+
+ ok ho@ deraadt@ markus@
+
+2004-03-17 16:05 brad
+
+ * doi.h, ike_quick_mode.c, ipsec.c, isakmp_cfg.c, isakmp_doi.c,
+ message.c, util.h: MFC: Fix by hshoexer@
+
+ Fix payload handling flaws found by cloder@. Based on initial
+ patch by cloder@.
+
+ ok deraadt@ hshoexer@
+
+2004-03-17 15:59 brad
+
+ * doi.h, ike_quick_mode.c, ipsec.c, isakmp_cfg.c, isakmp_doi.c,
+ message.c, util.h: MFC: Fix by hshoexer@
+
+ Fix payload handling flaws found by cloder@. Based on initial
+ patch by cloder@.
+
+ ok deraadt@ hshoexer@
+
+2004-03-17 12:10 ho
+
+ * ike_auth.c: For consistency and to avoid a rare memory leak, the
+ result from ike_auth_get_key() should always be released after
+ use. Found and ok hshoexer@.
+
+2004-03-15 17:34 hshoexer
+
+ * monitor.c: Properly check succes of chroot().
+
+ ok ho@
+
+2004-03-15 17:29 hshoexer
+
+ * monitor.c, monitor.h: Remove unused code.
+
+ ok ho@
+
+2004-03-11 17:56 hshoexer
+
+ * isakmp_cfg.c: Fix a memleak.
+
+ ok ho@
+
+2004-03-11 00:08 hshoexer
+
+ * doi.h, ipsec.c, isakmp_doi.c, message.c, util.h: Fix payload
+ handling flaws found by cloder@. Based on initial patch by
+ cloder@. Testing by markus@ cloder@ hshoexer@.
+
+ ok ho@
+
+2004-03-10 17:10 hshoexer
+
+ * message.c: Plug up memory leak.
+
+ ok ho@
+
+2004-03-10 12:17 hshoexer
+
+ * message.c: Reduce some noise on receipt of an invalid spi.
+
+ ok ho@
+
+2004-03-10 10:28 ho
+
+ * pf_key_v2.c: Fix for PR2429, from Clemens Wittinger.
+
+2004-03-09 22:42 hshoexer
+
+ * message.c: Plug memleaks, found by cloder@.
+
+ ok ho@
+
+2004-02-27 20:14 hshoexer
+
+ * ipsec.c: Remove dead code.
+
+ ok ho@
+
+2004-02-27 20:07 hshoexer
+
+ * conf.c, isakmpd.conf.5: Add group 14 (modp2048) to predefined
+ suites. Manpage also updated. ok ho@
+
+2004-02-27 11:16 ho
+
+ * ike_phase_1.c, ike_quick_mode.c, sa.c, sa.h: (C)-2004
+
+2004-02-27 10:01 ho
+
+ * ike_phase_1.c, ike_quick_mode.c, sa.c, sa.h: Follow RFC 2408 more
+ closely regarding how to better check the proposal returned by
+ the other peer (the responder). Some implementations (notably the
+ Cisco PIX) does not follow a SHOULD in section 4.2 of the RFC.
+ With certain proposal combinations this caused us to setup the
+ wrong SA resulting in us being unable to process incoming IPsec
+ traffic (over this tunnel).
+
+ Tested against a number of different IKE implementations.
+ hshoexer@ ok.
+
+2004-02-26 16:27 hshoexer
+
+ * regress/rsakeygen/rsakeygen.c: remove unused code. noticed by
+ ho@ ok ho@
+
+2004-02-26 06:52 jmc
+
+ * isakmpd.conf.5: tweak; ok hshoexer@
+
+2004-02-25 17:01 hshoexer
+
+ * init.c, isakmpd.conf.5, log.c, log.h, regress/b2n/Makefile,
+ regress/crypto/Makefile, regress/crypto/cryptotest.c,
+ regress/dh/Makefile, regress/ec2n/Makefile,
+ regress/group/Makefile, regress/prf/Makefile,
+ regress/rsakeygen/Makefile, regress/rsakeygen/rsakeygen.c,
+ regress/util/Makefile: Add and document configuration options
+ Logverbose and Loglevel. As log.c now depends on conf.c and some
+ regression tests use log.c, add conf.c to Makefiles where
+ necessary.
+
+ ok ho@
+
+2004-02-20 12:31 hshoexer
+
+ * ike_quick_mode.c: More small adjustments of log messages.
+
+2004-02-20 10:46 hshoexer
+
+ * ike_quick_mode.c: Fix some double free errors. While around,
+ adjust a log message. ok ho@
+
+2004-02-19 16:35 hshoexer
+
+ * isakmpd.c: small cleanup of log messages. ok ho@
+
+2004-02-19 10:54 ho
+
+ * isakmpd.c, log.c, log.h: With -d, SIGINT should do a clean
+ shutdown. Without -d, logs should be sent to syslog, level
+ LOG_INFO.
+
+2004-02-19 10:46 ho
+
+ * isakmpd.c: Cleanup.
+
+2004-02-16 21:40 markus
+
+ * exchange.c: check for isakmp_sa->transport != NULL; noticed by
+ bluhm at genua.de ok hshoexer@
+
+2004-02-11 09:55 jmc
+
+ * samples/VPN-3way-template.conf: typo; from Olivier Cherrier;
+
+2004-02-05 12:01 hshoexer
+
+ * exchange.c: small logging cleanup and improvement requested by
+ markus ok ho@ markus@
+
+2004-01-26 15:56 niklas
+
+ * regress/exchange/run.pl: Added 2-clause license
+
+2004-01-24 00:08 jmc
+
+ * isakmpd.8: `Ns' implies `No', so `Ns No' -> `Ns'; (even simpler
+ in adduser(8)) discussed with todd@
+
+2004-01-16 11:51 hshoexer
+
+ * exchange.c, ike_quick_mode.c, isakmpd.8, isakmpd.c, log.c, log.h:
+ Added -v option. Enables logging of successful exchange
+ completion. ok ho@
+
+2004-01-16 01:00 brad
+
+ * exchange.c, ipsec.c, message.c: Fixes a few message handling
+ flaws in isakmpd as reported by Thomas Walpuski.
+
+ ok deraadt@ hshoexer@
+
+2004-01-13 23:50 brad
+
+ * crypto.c, crypto.h, exchange.c, ipsec.c, message.c: Fixes a few
+ message handling flaws in isakmpd as reported by Thomas Walpuski.
+
+ ok deraadt@ hshoexer@
+
+2004-01-09 11:03 hshoexer
+
+ * regress/exchange/run.sh: call nc correctly (nc has changed a
+ while ago). ok markus@
+
+2004-01-06 01:22 hshoexer
+
+ * conf.c, sa.c: small typos fixed.
+
+ ok markus@
+
+2004-01-06 01:09 hshoexer
+
+ * x509.c: Remove redundant test for file types. Noted by Stefan
+ Paletta. While around, fix typos in log messages.
+
+ Both ok markus@
+
+2004-01-03 17:38 ho
+
+ * ipsec.c: Be more careful with INITIAL-CONTACT and do not delete
+ SPIs when getting an INVALID-SPI notification. Issues noted by
+ Thomas Walpuski. markus@ ok.
+
+2003-12-22 19:13 markus
+
+ * crypto.h: use AES_BLOCK_SIZE only for USE_AES; report
+ martti.kuparinen@iki.fi; ok ho@
+
+2003-12-18 03:03 ho
+
+ * transport.c: Mention the exchange name when giving up on a
+ message. Suggested by Michael Coulter.
+
+2003-12-15 11:06 hshoexer
+
+ * ipsec.c, ipsec_num.cst, math_group.c, math_group.h: Support for
+ groups modp2048, modp3072, modp4096, modp6144 and modp8192 (IDs
+ 14 to 18).
+
+ ok ho@
+
+2003-12-14 15:50 ho
+
+ * log.c, util.c, util.h: Log the actual port for src and dst, don't
+ assume it's always 500.
+
+2003-12-14 15:34 ho
+
+ * sysdep/linux/sysdep.c: Make isakmpd work on big endian linux
+ machines. From Sebastian Klemke. Also, a few style nits and a
+ better error message text.
+
+2003-12-05 14:17 ho
+
+ * message.c: Style nits
+
+2003-12-04 23:44 hshoexer
+
+ * message.c: Validate SPIs presented in DELETE messages of the
+ informational exchange. ok markus@
+
+2003-12-04 22:13 miod
+
+ * ike_phase_1.c, isakmp_cfg.c: Typos
+
+2003-11-20 12:23 jmc
+
+ * isakmpd.8: use .Dv for AF_INET and AF_INET6 (kills ugly line
+ break); spotted by Alexey E. Suslikov;
+
+ also kill some .Pp's before displays/lists for better PostScript
+ output;
+
+2003-11-08 20:17 jmc
+
+ * init.c: typos from Jonathon Gray;
+
+2003-11-07 11:16 jmc
+
+ * x509.c, samples/VPN-3way-template.conf: adress -> address, and a
+ few more; all from Jonathon Gray;
+
+ (mvme68k/mvme88k) vs.c and (vax) if_le.c ok miod@ isakmpd ones ok
+ ho@
+End of changelog debian package isakmpd.20031107-1
+--------------------------------------------------
+
+2003-11-06 17:12 ho
+
+ * dnssec.c, exchange.c, field.c, if.c, ike_auth.c, ipsec.c, key.c,
+ log.c, message.c, message.h, monitor_fdpass.c, pf_key_v2.c,
+ policy.c, ui.c, x509.c, x509.h: Style nits.
+
+2003-11-06 16:55 ho
+
+ * exchange.c, message.c: Require encrypted messages are soon as we
+ have the keystate for it. Require DELETE payloads to be
+ accompanied by HASHes, and add validation for HASH payloads
+ without active exchanges. From Hans-Joerg Hoexer with various
+ modifications and suggestions from me and markus@. Ok markus@.
+
+2003-11-06 16:50 ho
+
+ * ipsec.c: spis[] type tweak. From Hans-Joerg Hoexer.
+
+2003-11-05 13:55 jmc
+
+ * isakmpd.conf.5: PFS: Perfect Forward Secrecy (RFC 2409); from
+ misc@ and ok markus@
+
+2003-11-05 13:31 jmc
+
+ * QUESTIONS: updated URL from Jared Yanovich;
+
+2003-10-25 22:47 mcbride
+
+ * isakmpd.policy.5: OpenSSL generates DNs with emailAddress, not
+ Email.
+
+2003-10-25 09:47 jmc
+
+ * isakmpd.8: receiveing -> receiving; from Jared Yanovich;
+
+2003-10-14 16:29 ho
+
+ * exchange.c, ike_auth.c, ike_phase_1.c, ipsec.c, isakmp_doi.c:
+ constant_lookup() to constant_name() cleanup. markus@ ok.
+
+2003-10-13 15:57 ho
+
+ * isakmpd.8, log.h, ui.c: Add a UI FIFO debug class. ok markus@
+ plus I think henning@
+
+2003-10-04 19:29 cloder
+
+ * ike_phase_1.c: Avoid crash on invalid config file (missing value
+ for LIFE_DURATION). OK ho@
+
+2003-09-26 17:59 aaron
+
+ * sysdep/freeswan/klips.c: Fix off-by-ones in format string for 's'
+ specifier; millert@, deraadt@ ok
+
+2003-09-26 13:29 cedric
+
+ * udp.c: don't listen to INADDR_ANY if Listen-on is specified.
+ patch from markus@, ok ho@
+
+2003-09-26 00:28 aaron
+
+ * monitor.c: Fix off-by-one out-of-bounds write; millert@ ok
+
+2003-09-25 16:15 cloder
+
+ * exchange.c, if.c: Fix one case of set length before realloc. Fix
+ another case of foo = realloc(foo...) and avoid possible memory
+ leaks. Avoid leaving things pointing to freed memory on failure.
+
+2003-09-24 13:12 markus
+
+ * crypto.c, crypto.h, regress/crypto/cryptotest.c: re-add AES, but
+ without using EVP; patch from Hans-Joerg.Hoexer at
+ yerbouti.franken.de; ok ho@ (interops with isakmpd+AES in OpenBSD
+ 3.4)
+
+2003-09-24 12:13 markus
+
+ * crypto.c, crypto.h, regress/crypto/cryptotest.c: back out EVP
+ change; causes fd leaks; ok cedric@
+
+End of changelog debian package isakmpd.20030907-1
+--------------------------------------------------
+
+2003-09-05 09:50 tedu
+
+ * monitor.c: socket leak on error paths. from Patrick Latifi. ok
+ deraadt@ ho@
+
+2003-09-02 20:15 ho
+
+ * conf.c, ipsec.c: A couple of nits. deraadt@ ok.
+
+2003-09-02 20:14 ho
+
+ * message.c: Require ISAKMP_FLAGS_ENC on phase 2 messages. ok
+ markus@, deraadt@.
+
+2003-09-02 20:11 ho
+
+ * sysdep/linux/: bitstring.h, sys/queue.h: For easier compilation
+ on linux systems. Requested by Thomas Walpuski.
+
+2003-08-28 16:43 markus
+
+ * Makefile, TO-DO, conf.c, crypto.c, crypto.h, isakmpd.conf.5,
+ regress/crypto/Makefile, regress/crypto/cryptotest.c: support AES
+ in phase 1, too. switch to OpenSSL EVP interface; with
+ Hans-Joerg.Hoexer at yerbouti.franken.de; ok ho@
+
+2003-08-20 16:43 ho
+
+ * samples/singlehost-west.conf: Zap an old "Identification" tag in
+ this sample config. I have no idea what it was supposed to do and
+ in any case there is no reference to this tag in current code.
+ Pointed out by Fridtjof Busse.
+
+2003-08-20 14:25 ho
+
+ * isakmpd.8: certpatch(8) can be used to create FQDN X509v3
+ extensions too. From Fridtjof Busse, via henning@. Thanks.
+
+
+End of changelog debian package isakmpd.20030820-1
+--------------------------------------------------
+
+2003-07-09 10:16 jmc
+
+ * isakmpd.conf.5, isakmpd.policy.5: - remove some .Ss's that worked
+ around the old blank line bug - remove some unnecessary .Pp's -
+ mdoc a list
+
+ ok ho@
+
+2003-06-20 11:14 ho
+
+ * transport.c: Be a bit more verbose when we give up on ever seeing
+ a response to the last message we sent out. In case we initiated
+ the exchange, one possible and common reason is a network level
+ problem (pf, routing, whatnot), if we're the responder, there is
+ also the possibility we were scanned by something like ike-scan.
+ markus@ ok.
+
+2003-06-17 23:56 millert
+
+ * sysdep/common/libsysdep/: strlcat.c, strlcpy.c: Sync with
+ share/misc/license.template and add missing DARPA credit where
+ applicable.
+
+2003-06-15 12:32 ho
+
+ * exchange.c: ID copying should happen earlier in exchange_finalize
+ so that we won't lose data during rekeying. From Jean-Francois
+ Dive.
+
+2003-06-14 13:47 ho
+
+ * message.c: allocate payload_node with calloc instead of malloc
+
+2003-06-13 05:50 brad
+
+ * ipsec.c: MFC: Fix from ho@
+
+ Do not crash on unsupported IPSec ID types, as noted by Eric
+ Boudrand.
+
+ deraadt@ millert@ ok
+
+2003-06-13 05:34 brad
+
+ * ipsec.c: MFC: Fix from ho@
+
+ Do not crash on unsupported IPSec ID types, as noted by Eric
+ Boudrand.
+
+ deraadt@ millert@ ok
+
+2003-06-10 18:41 deraadt
+
+ * conf.c, exchange.c, ike_auth.c, ike_phase_1.c, ike_quick_mode.c,
+ isakmp_cfg.c, log.c, monitor.c, monitor.h, pf_key_v2.c, policy.c,
+ transport.c, udp.c, x509.c: boring cleanups
+
+2003-06-10 14:21 ho
+
+ * ipsec.c: Do not crash on unsupported IPSec ID types, as noted by
+ Eric Boudrand.
+
+2003-06-04 09:31 ho
+
+ * exchange.c, ike_aggressive.c, ike_auth.c, ike_phase_1.c,
+ ike_quick_mode.c, init.c, ipsec.c, ipsec.h, isakmpd.8, isakmpd.c,
+ isakmpd.policy.5, libcrypto.c, libcrypto.h, message.c, message.h,
+ pf_key_v2.c, policy.c, policy.h, sa.c, sa.h, udp.c, x509.c,
+ x509.h, apps/certpatch/certpatch.8, apps/certpatch/certpatch.c,
+ regress/ec2n/ec2ntest.c, regress/hmac/hmactest.c: Remove the rest
+ of clauses 3 and 4. Approved by Niklas Hallqvist, Angelos D.
+ Keromytis and Niels Provos.
+
+2003-06-04 09:27 ho
+
+ * DESIGN-NOTES: Remove 3 and 4 from the "license to use"
+
+2003-06-03 17:20 ho
+
+ * sysdep/linux/: GNUmakefile.sysdep, sysdep-os.h, sysdep.c: Remove
+ clause 3. Approved by niklas@ and Thomas Walpuski.
+
+2003-06-03 17:02 ho
+
+ * sysdep/linux/README: Obsolete.
+
+2003-06-03 16:53 ho
+
+ * sysdep/: bsdi/GNUmakefile.sysdep, bsdi/Makefile.sysdep,
+ bsdi/sysdep-os.h, bsdi/sysdep.c, darwin/GNUmakefile.sysdep,
+ darwin/Makefile.sysdep, darwin/sysdep-os.h, darwin/sysdep.c,
+ freebsd/GNUmakefile.sysdep, freebsd/Makefile.sysdep,
+ freebsd/sysdep-os.h, freebsd/sysdep.c,
+ freeswan/GNUmakefile.sysdep, freeswan/Makefile.sysdep,
+ freeswan/klips.c, freeswan/klips.h, freeswan/sysdep-os.h,
+ freeswan/sysdep.c, netbsd/GNUmakefile.sysdep,
+ netbsd/Makefile.sysdep, netbsd/sysdep-os.h, netbsd/sysdep.c,
+ openbsd/GNUmakefile.sysdep, openbsd/Makefile.sysdep,
+ openbsd/keynote_compat.c, openbsd/sysdep-os.h, openbsd/sysdep.c:
+ Remove clauses 3 and 4. Approved by markus@ and niklas@.
+
+2003-06-03 16:52 ho
+
+ * sysdep/common/: blf.h, libsysdep/GNUmakefile, libsysdep/Makefile,
+ libsysdep/blowfish.c: Remove clauses 3 and 4. Approved by Niklas
+ Hallqvist and Niels Provos.
+
+2003-06-03 16:39 ho
+
+ * regress/Makefile, regress/check.sh, regress/b2n/b2ntest.c,
+ regress/crypto/cryptotest.c, regress/dh/dhtest.c,
+ regress/exchange/Makefile, regress/exchange/run.sh,
+ samples/Makefile, regress/group/grouptest.c,
+ regress/prf/prftest.c, regress/rsakeygen/Makefile,
+ regress/rsakeygen/rsakeygen.c, regress/util/utiltest.c,
+ regress/x509/Makefile, regress/x509/x509test.c: Remove clauses 3
+ and 4. Approved by Niklas Hallqvist and Niels Provos.
+
+2003-06-03 16:35 ho
+
+ * apps/: Makefile, certpatch/Makefile: Remove clauses 3 and 4.
+ Approved by Niklas Hallqvist and Niels Provos.
+
+2003-06-03 16:34 ho
+
+ * apps/keyconv/: Makefile, keyconv.8, keyconv.c, keyvalues.h:
+ Remove clause 3.
+
+2003-06-03 16:29 ho
+
+ * features/: aggressive, dnssec, ec, isakmp_cfg, policy, privsep,
+ x509: Remove clause 3. Approved by niklas@
+
+2003-06-03 16:28 ho
+
+ * GNUmakefile, Makefile, app.c, app.h, attribute.c, attribute.h,
+ cert.c, cert.h, conf.c, conf.h, connection.c, connection.h,
+ constants.c, constants.h, cookie.c, cookie.h, crypto.c, crypto.h,
+ dh.c, dh.h, dnssec.c, dnssec.h, doi.c, doi.h, exchange.h,
+ exchange_num.cst, field.c, field.h, genconstants.sh,
+ genfields.sh, gmp_util.c, gmp_util.h, hash.c, hash.h, if.c, if.h,
+ ike_aggressive.h, ike_auth.c, ike_auth.h, ike_main_mode.c,
+ ike_main_mode.h, ike_phase_1.h, ike_quick_mode.h, init.c, init.h,
+ ipsec_doi.h, ipsec_fld.fld, ipsec_num.cst, isakmp.h,
+ isakmp_cfg.c, isakmp_cfg.h, isakmp_doi.c, isakmp_doi.h,
+ isakmp_fld.fld, isakmp_num.cst, isakmpd.conf.5, log.c, log.h,
+ math_2n.c, math_2n.h, math_ec2n.c, math_ec2n.h, math_group.c,
+ math_group.h, math_mp.h, monitor.c, monitor.h, pf_key_v2.h,
+ prf.c, prf.h, sysdep.h, timer.c, timer.h, transport.c,
+ transport.h, udp.h, ui.c, ui.h, util.c, util.h: Remove clauses 3
+ and 4. With approval from Niklas Hallqvist and Niels Provos.
+
+2003-06-03 15:16 jmc
+
+ * isakmpd.8, isakmpd.conf.5, isakmpd.policy.5: - section reorder -
+ some mdoc fixes
+
+2003-06-03 14:51 ho
+
+ * conf.c, constants.c, dnssec.c, exchange.c, ike_auth.c,
+ ike_phase_1.c, ike_quick_mode.c, ipsec.c, log.c, message.c,
+ policy.c, sa.c, udp.c, x509.c: Cleanup. Use 'sizeof variable'
+ instead of magic constants.
+
+2003-06-03 03:52 millert
+
+ * sysdep/common/libsysdep/: strlcat.c, strlcpy.c: Use an ISC-tyle
+ license for all my code; it is simpler and more permissive.
+
+2003-06-02 22:06 millert
+
+ * sysdep/freeswan/sys/queue.h: Remove the advertising clause in the
+ UCB license which Berkeley rescinded 22 July 1999. Proofed by
+ myself and Theo.
+
+2003-05-18 23:26 ho
+
+ * monitor.c: Add some path sanitation; only permit write operations
+ to /tmp, /var/tmp and /var/run. Opens in /etc/isakmpd/ are
+ read-only. Any other path is invalid. markus@ ok.
+
+2003-05-18 22:46 ho
+
+ * init.c: Style tweak.
+
+2003-05-18 22:39 ho
+
+ * sa.c: Add a debug message to sa_reinit() to indicate when we
+ renegotiate active connections.
+
+2003-05-18 22:09 ho
+
+ * monitor_fdpass.c: Forgot to remove a couple of debug messages
+
+2003-05-18 22:06 ho
+
+ * udp.c: struct sockaddr is not large enough in itself to contain
+ the address value. Switching to sockaddr_storage makes interface
+ rescanning work properly. niklas@ ok.
+
+2003-05-18 21:37 ho
+
+ * conf.c, ike_auth.c, isakmpd.c, log.c, monitor.c, monitor.h,
+ monitor_fdpass.c, pf_key_v2.c, policy.c: More isakmpd privsep
+ work. X509 private keys are now kept in the privileged process
+ only. Various cleanup and bugfixes. markus@ ok
+
+2003-05-18 20:16 ho
+
+ * GNUmakefile, pf_key_v2.c, udp.c, sysdep/linux/GNUmakefile.sysdep,
+ sysdep/linux/sysdep-os.h, sysdep/linux/sysdep.c: Sysdep for
+ native Linux IPSec, 2.5 and later. From Thomas Walpuski, with
+ various tweaks by me. niklas@ ok.
+
+2003-05-17 19:39 ho
+
+ * monitor.h, monitor_fdpass.c: Better return codes from mm_send_fd
+ and mm_receive_fd
+
+2003-05-17 19:32 ho
+
+ * monitor_fdpass.c: Use log_error(), not log_fatal(). Style.
+
+2003-05-17 19:26 jmc
+
+ * isakmpd.conf.5: tweak; ok ho@
+
+2003-05-16 22:31 ho
+
+ * init.c, isakmpd.conf.5, sa.c, sa.h: If the "Renegotiate-on-HUP"
+ tag is defined in the [General] section, a HUP signal (or "R" to
+ the FIFO) will also renegotiate all Phase 2 SAs, i.e all
+ connections. ok niklas@, tested and ok kjell@.
+
+2003-05-15 05:20 ho
+
+ * ike_auth.c: Correct a two year old typo, which might actually
+ make setsockopt(..., IP_IPSEC_LOCAL_AUTH, ...) start working.
+
+2003-05-15 04:28 ho
+
+ * exchange.c, ike_auth.c, sa.c, sa.h: Cleanup. Do not store the
+ private key in either the exchange or sa structs.
+
+2003-05-15 04:08 ho
+
+ * ike_auth.c: Work around some OpenSSL BIO "features" to read the
+ key correctly.
+
+2003-05-15 04:04 ho
+
+ * monitor.c: Proper exit of the monitor process.
+
+2003-05-15 03:51 ho
+
+ * monitor.c: wait() for the child process
+
+2003-05-15 02:28 ho
+
+ * Makefile, conf.c, conf.h, ike_auth.c, init.c, isakmpd.c, log.c,
+ monitor.c, monitor.h, monitor_fdpass.c, pf_key_v2.c, policy.c,
+ udp.c, ui.c, util.c, features/privsep, sysdep/openbsd/sysdep.c:
+ Start of privilege separation for isakmpd. There are some kinks
+ left, so keep it default disabled for now. markus@ says ok to
+ commit.
+
+2003-05-15 02:24 ho
+
+ * log.h: (c)
+
+2003-05-15 01:44 kjell
+
+ * pf_key_v2.c: properly terminate debug string (levels >=40) Use
+ "%.*s" as suggested by Niklas. ok ho@. Lost by kjell. oked ho@.
+ lost by kjell again. oked ho@
+
+2003-05-15 01:29 ho
+
+ * features/policy: Remove the .if/.endif stuff that gmake does not
+ understand. Replace with a comment about needing keynote for
+ policy.
+
+2003-05-14 22:49 ho
+
+ * GNUmakefile, Makefile, sysdep/freeswan/GNUmakefile.sysdep,
+ sysdep/freeswan/Makefile.sysdep, sysdep/freeswan/README,
+ sysdep/freeswan/klips.c, sysdep/freeswan/klips.h,
+ sysdep/freeswan/sysdep-os.h, sysdep/freeswan/sysdep.c,
+ sysdep/freeswan/sys/queue.h, sysdep/linux/GNUmakefile.sysdep,
+ sysdep/linux/Makefile.sysdep, sysdep/linux/README,
+ sysdep/linux/klips.c, sysdep/linux/klips.h,
+ sysdep/linux/sysdep-os.h, sysdep/linux/sysdep.c: Call the
+ FreeS/WAN sysdep 'freeswan'. The 'linux' sysdep will be native
+ Linux IPSec.
+
+2003-05-14 20:11 ho
+
+ * conf.c, conf.h, ike_auth.c: Default public key directory
+ definition sanity.
+
+2003-05-14 20:10 ho
+
+ * policy.c, policy.h: Policy file default defined twice, kill the
+ local copy.
+
+2003-05-14 20:08 ho
+
+ * isakmpd.c: Fix a typo (in unused code).
+
+2003-05-14 19:37 ho
+
+ * ipsec.c, ipsec_num.cst, pf_key_v2.c, policy.c, sa.c: I did not
+ test this enough. Unbreak.
+
+2003-05-12 23:48 ho
+
+ * isakmp_num.cst: Update with some data for NAT-T specific payload
+ types, IKEv2 notifications, ISAKMP EAP code and types, plus fix
+ an old typo.
+
+2003-05-12 23:43 ho
+
+ * ipsec.c, pf_key_v2.c, policy.c, sa.c: AES -> AES_128_CBC
+
+2003-05-12 23:42 ho
+
+ * ipsec_num.cst: Add two more encapsulation types (UDP encap,
+ potential future NAT-T) Add BLOCK_SIZE attribute Rename
+ IPSEC_ESP_AES -> IPSEC_ESP_AES_128_CBC.
+
+2003-05-12 01:17 ho
+
+ * genconstants.sh: Slight style fix for .cst files. Permit comments
+ also after a definition.
+
+2003-05-11 04:16 markus
+
+ * pf_key_v2.c: fix ID-type for ipv6; ok niklas; report fries
+
+2003-05-10 23:13 jmc
+
+ * isakmpd.8, isakmpd.conf.5: typos;
+
+2003-04-30 17:15 jason
+
+ * conf.c: cast size_t to unsigned long and use %lu;ok ho
+
+2003-04-27 13:17 ho
+
+ * isakmpd.8: Describe the 'C set' FIFO command better. (PR#3148,
+ also)
+
+2003-04-27 13:16 ho
+
+ * ui.c: Make the 'C set' FIFO command work as expected. PR#3148.
+
+2003-04-14 15:08 ho
+
+ * isakmpd.c: Unlink FIFO and pid files on clean shutdown. PR#3199
+
+2003-04-14 12:22 ho
+
+ * pf_key_v2.c: More snprintf style
+
+2003-04-14 12:14 ho
+
+ * pf_key_v2.c: A "%d" is 12 chars, not 10. Use sizeof num instead
+ of '10' in snprintf. From Theo.
+
+2003-04-09 17:46 ho
+
+ * x509.c: Less noise for missing crl dir, demoted to debug message.
+
+2003-03-21 16:13 markus
+
+ * isakmpd.conf.5: document [initiator-id] section;
+ richb@timestone.com.au; ok ho@, jmc@
+
+2003-03-20 20:39 margarida
+
+ * isakmp_cfg.c: Pull patch from current: Fix by ho@. Proper
+ id_string for SET/ACK responder, plus attr payload fixes.
+
+ ok millert@ markus@ ho@
+
+2003-03-16 09:13 matthieu
+
+ * samples/: VPN-east.conf, VPN-west.conf: secrity -> security. Ok
+ ho@
+
+2003-03-14 15:49 ho
+
+ * math_group.c, transport.c, sysdep/common/blf.h,
+ sysdep/common/libsysdep/blowfish.c: Spelling fixes from david@.
+ jmc@ ok.
+
+2003-03-13 14:24 ho
+
+ * ike_auth.c: Might as well do blinding here too.
+
+2003-03-13 11:31 ho
+
+ * util.c: Avoid "j += snprintf()". niklas@ ok.
+
+2003-03-06 21:29 jmc
+
+ * isakmpd.conf.5, isakmpd.policy.5: .Xr typos;
+
+ ok deraadt@
+
+2003-03-06 15:22 cedric
+
+ * util.c: fix text2sockaddr() when HAVE_GETNAMEINFO is false and
+ port is NULL. ok ho@
+
+2003-03-06 14:48 cedric
+
+ * field.c: "len" is decremented too early, so the second argument
+ of the snprintf call is too small on last run of the loop. ok
+ ho@
+
+2003-03-06 14:32 ho
+
+ * exchange.c: Bad cut'n'paste msg plus style fixes.
+
+2003-03-06 10:56 ho
+
+ * util.c: Less ambiguous l-value usage. Noted by cedric@
+
+2003-03-06 05:07 david
+
+ * apps/keyconv/keyconv.8: date should be written formally: .Dd
+ Month day, year ok henning@ jmc@
+
+2003-03-03 17:51 ho
+
+ * isakmpd.conf.5: Re-add the BUGS section; the RFCs still do not
+ permit differing DH groups in the same proposal. This time,
+ mention that this also applies to mixing PFS and non-PFS suites.
+
+2003-02-26 23:55 ho
+
+ * samples/VPN-west.conf: Typo/pasto. Spotted by Tim Donahue.
+
+2003-02-26 09:17 david
+
+ * exchange.c: IPsec is written ``IPsec'', not ``IPSec''. ok ho@
+
+2003-02-24 13:01 markus
+
+ * pf_key_v2.c: pf_key_v2_flow: typo in debug msg (KAME)
+
+2003-02-22 07:57 kjell
+
+ * README: typo: noneheless->nontheless
+
+2003-02-22 07:56 kjell
+
+ * isakmpd.8, isakmpd.conf.5: Clarify some language, grammar. ho@
+ okayed this many moons ago, and I forgot all about it.
+
+2003-02-12 16:11 markus
+
+ * if.c, if.h, udp.c: better error checking on bind(); from
+ Alexander_Bluhm at genua.de; ok ho@
+
+2003-02-05 11:29 jmc
+
+ * isakmpd.8: typos; isakmpd(8) ok niklas@, mailwrapper(8) help
+ kjell@
+
+2003-02-04 21:02 markus
+
+ * conf.c: don't set the Transform for Default-phase-1-configuration
+ twice, ok ho@
+
+2003-02-04 21:02 markus
+
+ * conf.h: default to 3DES-SHA-RSA_SIG (same as in OpenBSD 3.2); ok
+ ho@
+
+2003-01-22 16:13 ho
+
+ * ike_auth.c: Typo.
+
+2003-01-20 20:52 deraadt
+
+ * isakmpd.policy.5: typos; alan@alanday.com
diff --git a/keyexchange/isakmpd-20041012/debian/README.Debian b/keyexchange/isakmpd-20041012/debian/README.Debian
new file mode 100644
index 0000000..5ed5128
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/README.Debian
@@ -0,0 +1,17 @@
+State of the package / isakmpd port to linux
+--------------------------------------------
+The port is operational and is included in upstream, from various sources.
+
+
+Where to start
+--------------
+- isakmpd.conf man pages.
+- configuration examples.
+- openbsd isakmpd documentation.
+
+caution note
+------------
+- keynote is used to check for all policy components. For exemple, if acting
+ as initiator, isakmpd will send the isakmpd.conf configured proposals but
+ will only check the received proposal with the rules enforced in isakmpd.policy.
+
diff --git a/keyexchange/isakmpd-20041012/debian/changelog b/keyexchange/isakmpd-20041012/debian/changelog
new file mode 100644
index 0000000..1883efc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/changelog
@@ -0,0 +1,153 @@
+isakmpd (20041012-4) unstable; urgency=high
+
+ * Fix replay protection (CVE-2006-4436)
+ Thanks to Stefan Fritsch <sf@fritsch.de> (Closes: #385894)
+
+ -- Jochen Friedrich <jochen@scram.de> Mon, 4 Sep 2006 18:41:00 +0200
+
+isakmpd (20041012-3) unstable; urgency=low
+
+ * Fix NAT-T RFC support.
+ * Remove superfluos header from packet dump so tcpdump and ethereal
+ can read the dump.
+
+ -- Jochen Friedrich <jochen@scram.de> Mon, 28 Aug 2006 17:14:47 +0200
+
+sakmpd (20041012-2) unstable; urgency=low
+
+ * New maintainer (Closes: #358800)
+ * Replace SADB_X_SPDADD by SADB_X_SPDUPDATE (Closes: #346214)
+ * Fix NAT-T (Closes: #324753)
+ * Fix openssl incompatibility with version 0.9.8b (Closes: #334624)
+ * Fix dependencies (Closes: #320393, #325849)
+ * gcc compiler fixes (Closes: #318241)
+ * Update standards version to 3.7.2
+
+ -- Jochen Friedrich <jochen@scram.de> Tue, 21 Feb 2006 14:26:40 +0100
+
+isakmpd (20041012-1) unstable; urgency=high
+
+ * new upstream cvs merge.
+ * add setsockopt to properly configure udp encap socket.
+ * add proper source port in nat-t sadb set (thanks to Thomas Walpuski).
+ * DPD now works (closes: #258479).
+ * NAT-T now works (closes: #269851).
+ * remove double dependency on libkeynote0 (closes: #272377).
+
+ -- Jean-Francois Dive <jef@debian.org> Tue, 7 Sep 2004 11:28:18 +0200
+
+isakmpd (20040628-1) unstable; urgency=high
+
+ * New upstream cvs merge.
+ * Enabled DPD.
+ * Enabled NAT-T + added support for linux nat-t pfkey msgs.
+ * Fix payload handling denial-of-service vuln (closes: #239739);
+ * Add spd cleartext entry (thanks to Vincent Bernat). (closes: #243990).
+ * Add dependency on linux-kernel-headers (closes: #238793).
+ * Add man page for isakmpd.policy.
+ * No issue with Renegotiate-on-HUP (closes: #255507).
+ * x509v3.cnf provided (closes: #238542).
+ * Added certpatch utility (closes: #231743).
+ * Fixed pcap support (closes: #238543).
+
+ -- Jean-Francois Dive <jef@debian.org> Mon, 5 Jul 2004 23:32:47 +0200
+
+isakmpd (20040204-1) unstable; urgency=low
+
+ * Provide ike-server (closes: #223784).
+ * Fixes for big indian systems (thanks to Sebastian Klemke).
+ (closes: #223845).
+ * Fix for certificates file access on non ext2 enabled kernel
+ systems, thanks to jochen. (closes: #225474).
+ * Update kernel version informations. (closes: #229795).
+ * New upstream cvs merge.
+ * Added missing man page isakmpd.policy(5) (thanks to Toni Mueller).
+ (closes: #231123).
+
+ -- Jean-Francois Dive <jef@debian.org> Sun, 8 Feb 2004 20:55:34 +0100
+
+isakmpd (20031107-2) unstable; urgency=high
+
+ * SECURITY fix for INITIAL_CONTACT handeling. (previous
+ release actually did fixed INVALID_SPI informational exchange
+ security issue). The problem is the exact same nature for both
+ type of informational messages: because the end result is SA
+ deletation, the HASH payload should be in the message and checked.
+
+ -- Jean-Francois Dive <jef@debian.org> Thu, 13 Nov 2003 14:54:01 +0100
+
+isakmpd (20031107-1) unstable; urgency=high
+
+ * new upstream cvs merge.
+ * SECURITY fix for HASH payload handeling (closes: #219864).
+ * SECURITY fix handeling of quick mode exchange encryption (it now
+ does require quick mode to be encrypted both Rx/Tx).
+ * SECURITY fix for INITIAL_CONTACT handeling (did not check for
+ mandatory HASH payload).
+ * Updated linux kernel header for interop with debian x86 kernels.
+ * Fix issues with policy handeling in keynote.
+
+ -- Jean-Francois Dive <jef@debian.org> Thu, 13 Nov 2003 11:05:09 +0100
+
+isakmpd (20030907-1) unstable; urgency=high
+
+ * new upstream cvs merge.
+ * Fixed kernel interface due to ABI changes in linux IPSec.
+ * Fixed keynote issue.
+
+ -- Jean-Francois Dive <jef@debian.org> Wed, 10 Sep 2003 22:47:17 +0200
+
+isakmpd (20030718-1) unstable; urgency=high
+
+ * New upstream version.
+ * Merged new upstream linux native build support.
+ * Added fine grained selector support to upstream linux native sysdep.
+ * Removed useless libc and kernel headers.
+ * Removed libdes.
+ * Added generated upstream changelog (generated by cvs2cl.pl).
+
+ -- Jean-Francois Dive <jef@debian.org> Tue, 22 Jul 2003 12:15:30 +0200
+
+isakmpd (20030119-2) unstable; urgency=low
+
+ * Fixed init script (closes: #188086).
+ * Added support for Protocol and Port text definition in ID handeling.
+ (expl: Protocol = icmp instead of Protocol = 1).
+
+ -- Jean-Francois Dive <jef@debian.org> Mon, 9 Jun 2003 14:11:02 +0200
+
+isakmpd (20030119-1) unstable; urgency=low
+
+ * Changed version number to a sane format.
+
+ -- Jean-Francois Dive <jef@debian.org> Thu, 20 Mar 2003 18:46:56 +0100
+
+isakmpd (19012003-4) unstable; urgency=low
+
+ * Fixed source tree clean issues (libdes, libsysdep) (closes: #184295).
+ * Added diff to package upload.
+
+ -- Jean-Francois Dive <jef@debian.org> Tue, 18 Mar 2003 17:30:57 +0100
+
+isakmpd (19012003-3) unstable; urgency=low
+
+ * switched libdes copyright from copyright.libdes to
+ copyright file.
+
+ -- Jean-Francois Dive <jef@debian.org> Thu, 20 Feb 2003 13:10:54 +1100
+
+isakmpd (19012003-2) unstable; urgency=low
+
+ * Added reference to BSD license and libdes license.
+ * Renmoved double dependency on libssl.
+ * Removed /usr/doc link.
+ * Added lintian overrides.
+
+ -- Jean-Francois Dive <jef@debian.org> Sun, 26 Jan 2003 00:36:40 +1100
+
+isakmpd (19012003-1) unstable; urgency=low
+
+ * Inital debianization (Closes: #163904).
+
+ -- Jean-Francois Dive <jef@debian.org> Sun, 26 Jan 2003 00:36:40 +1100
+
diff --git a/keyexchange/isakmpd-20041012/debian/control b/keyexchange/isakmpd-20041012/debian/control
new file mode 100644
index 0000000..ba34296
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/control
@@ -0,0 +1,17 @@
+Source: isakmpd
+Maintainer: Jochen Friedrich <jochen@scram.de>
+Priority: optional
+Section: net
+Standards-Version: 3.7.2
+Build-Depends: debhelper (>= 5), libkeynote-dev, libssl-dev, libgmp3-dev, libpcap-dev, linux-kernel-headers
+
+Package: isakmpd
+Priority: optional
+Section: net
+Architecture: any
+Provides: ike-server
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: The Internet Key Exchange protocol openbsd implementation
+ IKE is a protocol which allow to exchange security information between
+ to peers. This implementation requires the native linux ipsec support.
+
diff --git a/keyexchange/isakmpd-20041012/debian/copyright b/keyexchange/isakmpd-20041012/debian/copyright
new file mode 100644
index 0000000..f418b06
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/copyright
@@ -0,0 +1,21 @@
+This package have been packaged by Jean-Francois Dive <jef@debian.org> as
+isakmpd. The upstream source of isakmpd can be found at www.openbsd.org
+
+This package is now maintained by Jochen Friedrich <jochen@scram.de>
+
+- This package links against openssl.
+- This package include linux kernel include files for interface definition
+ purposes. This should mean that GPL does not apply for this distribution.
+- This package include libdes from the openbsd tree which have the same
+ license as openssl, please refer to the following license statement for details.
+
+This is isakmpd, a BSD-licensed ISAKMP/Oakley (a.k.a. IKE)
+implementation. It's written by Niklas Hallqvist and Niels Provos,
+funded by Ericsson Radio Systems AB. Isakmpd's home is in the
+OpenBSD main source tree under src/sbin/isakmpd. Look at
+http://www.openbsd.org/ for details on how to get OpenBSD source.
+
+The isakmpd license is the BSD license, please refer to
+/usr/share/common-license/BSD for details. The few code modification in isakmpd
+(linux support) are authored by Jean-Francois Dive and Jochen Friedrich
+and are release on the same license as isakmpd itself.
diff --git a/keyexchange/isakmpd-20041012/debian/isakmpd.dirs b/keyexchange/isakmpd-20041012/debian/isakmpd.dirs
new file mode 100644
index 0000000..de7adf9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/isakmpd.dirs
@@ -0,0 +1,13 @@
+usr/sbin
+usr/bin
+etc/isakmpd
+etc/isakmpd/certs
+etc/isakmpd/crls
+etc/isakmpd/ca
+etc/isakmpd/pubkeys/ipv4
+etc/isakmpd/pubkeys/ipv6
+etc/isakmpd/pubkeys/fqdn
+etc/isakmpd/pubkeys/ufqdn
+etc/isakmpd/private
+usr/share/doc/isakmpd/samples
+usr/share/lintian/overrides
diff --git a/keyexchange/isakmpd-20041012/debian/isakmpd.init b/keyexchange/isakmpd-20041012/debian/isakmpd.init
new file mode 100644
index 0000000..57de3d4
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/isakmpd.init
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+DAEMON=/usr/sbin/isakmpd
+PIDFILE=/var/run/isakmpd.pid
+
+test -f $DAEMON || exit 0
+
+case "$1" in
+ start)
+ echo -n "Starting OpenBSD isakmpd: "
+ start-stop-daemon --start --verbose --pidfile $PIDFILE --exec $DAEMON > /dev/null 2>&1
+ echo "done"
+ ;;
+ stop)
+ echo -n "Stopping OpenBSD isakmpd: "
+ start-stop-daemon --stop --verbose --pidfile $PIDFILE --exec $DAEMON > /dev/null 2>&1
+ echo "done"
+ ;;
+ restart|force-reload)
+ echo -n "Restarting OpenBSD isakmpd: "
+ start-stop-daemon --stop --verbose --pidfile $PIDFILE --exec $DAEMON > /dev/null 2>&1
+ start-stop-daemon --start --verbose --pidfile $PIDFILE --exec $DAEMON > /dev/null 2>&1
+ echo "done"
+ ;;
+ *)
+ echo "Usage: /etc/init.d/isakmpd {start|stop|restart|force-reload}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/keyexchange/isakmpd-20041012/debian/isakmpd.lintian b/keyexchange/isakmpd-20041012/debian/isakmpd.lintian
new file mode 100644
index 0000000..7d9b585
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/isakmpd.lintian
@@ -0,0 +1,3 @@
+isakmpd: copyright-should-refer-to-common-license-file-for-gpl
+isakmpd: non-standard-dir-perm
+isakmpd: non-standard-file-perm
diff --git a/keyexchange/isakmpd-20041012/debian/rules b/keyexchange/isakmpd-20041012/debian/rules
new file mode 100755
index 0000000..d15e56a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/debian/rules
@@ -0,0 +1,73 @@
+#!/usr/bin/make -f
+
+export DH_COMPAT := 5
+
+b := $(CURDIR)/debian/isakmpd
+
+arrange: arrange-stamp
+arrange-stamp: install
+ dh_testdir
+ touch arrange-stamp
+
+binary: binary-stamp
+binary-stamp: binary-indep binary-arch
+ dh_testdir
+ touch binary-stamp
+
+binary-arch: binary-arch-stamp
+binary-arch-stamp: arrange
+ dh_testdir
+ dh_testroot
+ dh_installdocs -n DESIGN-NOTES QUESTIONS README README.PKI TO-DO $(CURDIR)/debian/README.Debian x509v3.cnf
+ cp $(CURDIR)/samples/*.conf $(b)/usr/share/doc/isakmpd/samples/
+ cp $(CURDIR)/samples/VPN-east.conf $(b)/etc/isakmpd/isakmpd.conf
+ cp $(CURDIR)/samples/policy $(b)/etc/isakmpd/isakmpd.policy
+ cp $(CURDIR)/isakmpd $(b)/usr/sbin/
+ cp $(CURDIR)/apps/certpatch/certpatch $(b)/usr/bin
+ cp $(CURDIR)/debian/isakmpd.lintian $(b)/usr/share/lintian/overrides/isakmpd
+ dh_installman isakmpd.8 isakmpd.conf.5 isakmpd.policy.5 apps/certpatch/certpatch.8
+ dh_installinit
+ dh_installchangelogs $(CURDIR)/debian/ChangeLog upstream
+ dh_compress
+ dh_fixperms
+ find $(b)/etc/isakmpd -type d | xargs chmod 0700
+ find $(b)/etc/isakmpd -type f | xargs chmod 0600
+ dh_strip
+ dh_installdeb
+ dh_perl
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+ touch binary-arch-stamp
+
+binary-indep: binary-indep-stamp
+binary-indep-stamp: arrange
+ dh_testdir
+ touch binary-indep-stamp
+
+build: build-stamp
+build-stamp: config
+ dh_testdir
+ $(MAKE)
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ $(MAKE) clean
+ dh_clean arrange-stamp binary-stamp binary-arch-stamp binary-indep-stamp build-stamp config-stamp install-stamp
+ find $(CURDIR) -type f -name ".depend" | xargs rm -f
+
+config: config-stamp
+config-stamp:
+ dh_testdir
+ touch config-stamp
+
+install: install-stamp
+install-stamp: build
+ dh_testdir
+ dh_installdirs
+ touch install-stamp
+
+.PHONY: arrange binary binary-arch binary-indep build clean config install
diff --git a/keyexchange/isakmpd-20041012/dh.c b/keyexchange/isakmpd-20041012/dh.c
new file mode 100644
index 0000000..afb41ba
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/dh.c
@@ -0,0 +1,82 @@
+/* $OpenBSD: dh.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: dh.c,v 1.5 1999/04/17 23:20:22 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+
+#include "sysdep.h"
+
+#include "math_group.h"
+#include "dh.h"
+#include "log.h"
+
+/*
+ * Returns the length of our exchange value.
+ */
+
+int
+dh_getlen(struct group *group)
+{
+ return group->getlen(group);
+}
+
+/*
+ * Creates the exchange value we are offering to the other party.
+ * Each time this function is called a new value is created, that
+ * means the application has to save the exchange value itself,
+ * dh_create_exchange should only be called once.
+ */
+int
+dh_create_exchange(struct group *group, u_int8_t *buf)
+{
+ if (group->setrandom(group, group->c))
+ return -1;
+ if (group->operation(group, group->a, group->gen, group->c))
+ return -1;
+ group->getraw(group, group->a, buf);
+ return 0;
+}
+
+/*
+ * Creates the Diffie-Hellman shared secret in 'secret', where 'exchange'
+ * is the exchange value offered by the other party. No length verification
+ * is done for the value, the application has to do that.
+ */
+int
+dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
+{
+ if (group->setraw(group, group->b, exchange, group->getlen(group)))
+ return -1;
+ if (group->operation(group, group->a, group->b, group->c))
+ return -1;
+ group->getraw(group, group->a, secret);
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/dh.h b/keyexchange/isakmpd-20041012/dh.h
new file mode 100644
index 0000000..afd00ad
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/dh.h
@@ -0,0 +1,43 @@
+/* $OpenBSD: dh.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */
+/* $EOM: dh.h,v 1.4 1999/04/17 23:20:24 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _DH_H_
+#define _DH_H_
+
+#include <sys/types.h>
+
+struct group;
+
+int dh_getlen(struct group *);
+int dh_create_exchange(struct group *, u_int8_t *);
+int dh_create_shared(struct group *, u_int8_t *, u_int8_t *);
+
+#endif /* _DH_H_ */
diff --git a/keyexchange/isakmpd-20041012/dnssec.c b/keyexchange/isakmpd-20041012/dnssec.c
new file mode 100644
index 0000000..b7ee75f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/dnssec.c
@@ -0,0 +1,293 @@
+/* $OpenBSD: dnssec.c,v 1.20 2004/06/14 09:55:41 ho Exp $ */
+
+/*
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include <openssl/rsa.h>
+
+#ifdef LWRES
+#include <lwres/netdb.h>
+#include <dns/keyvalues.h>
+#else
+#include <netdb.h>
+#endif
+
+#include "sysdep.h"
+
+#include "dnssec.h"
+#include "exchange.h"
+#include "ipsec_num.h"
+#include "libcrypto.h"
+#include "log.h"
+#include "message.h"
+#include "transport.h"
+#include "util.h"
+
+#ifndef DNS_UFQDN_SEPARATOR
+#define DNS_UFQDN_SEPARATOR "._ipsec."
+#endif
+
+/* adapted from <dns/rdatastruct.h> / RFC 2535 */
+struct dns_rdata_key {
+ u_int16_t flags;
+ u_int8_t protocol;
+ u_int8_t algorithm;
+ u_int16_t datalen;
+ unsigned char *data;
+};
+
+void *
+dns_get_key(int type, struct message *msg, int *keylen)
+{
+ struct exchange *exchange = msg->exchange;
+ struct rrsetinfo *rr;
+ struct dns_rdata_key key_rr;
+ char name[MAXHOSTNAMELEN];
+ in_addr_t ip4;
+ u_int8_t algorithm, *id, *umark;
+ size_t id_len;
+ int ret, i;
+
+ switch (type) {
+ case IKE_AUTH_RSA_SIG:
+ algorithm = DNS_KEYALG_RSA;
+ break;
+
+ case IKE_AUTH_RSA_ENC:
+ case IKE_AUTH_RSA_ENC_REV:
+ /* XXX Not yet. */
+ /* algorithm = DNS_KEYALG_RSA; */
+ return 0;
+
+ case IKE_AUTH_DSS:
+ /* XXX Not yet. */
+ /* algorithm = DNS_KEYALG_DSS; */
+ return 0;
+
+ case IKE_AUTH_PRE_SHARED:
+ default:
+ return 0;
+ }
+
+ id = exchange->initiator ? exchange->id_r : exchange->id_i;
+ id_len = exchange->initiator ? exchange->id_r_len : exchange->id_i_len;
+ memset(name, 0, sizeof name);
+
+ if (!id || id_len == 0) {
+ log_print("dns_get_key: ID is missing");
+ return 0;
+ }
+ /* Exchanges (and SAs) don't carry the ID in ISAKMP form */
+ id -= ISAKMP_GEN_SZ;
+ id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF;
+
+ switch (GET_ISAKMP_ID_TYPE(id)) {
+ case IPSEC_ID_IPV4_ADDR:
+ /* We want to lookup a KEY RR in the reverse zone. */
+ if (id_len < sizeof ip4)
+ return 0;
+ memcpy(&ip4, id + ISAKMP_ID_DATA_OFF, sizeof ip4);
+ snprintf(name, sizeof name, "%d.%d.%d.%d.in-addr.arpa.", ip4
+ >> 24, (ip4 >> 16) & 0xFF, (ip4 >> 8) & 0xFF, ip4 & 0xFF);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ /* XXX Not yet. */
+ return 0;
+ break;
+
+ case IPSEC_ID_FQDN:
+ if ((id_len + 1) >= sizeof name)
+ return 0;
+ /* ID is not NULL-terminated. Add trailing dot and NULL. */
+ memcpy(name, id + ISAKMP_ID_DATA_OFF, id_len);
+ *(name + id_len) = '.';
+ *(name + id_len + 1) = '\0';
+ break;
+
+ case IPSEC_ID_USER_FQDN:
+ /*
+ * Some special handling here. We want to convert the ID
+ * 'user@host.domain' string into 'user._ipsec.host.domain.'.
+ */
+ if ((id_len + sizeof(DNS_UFQDN_SEPARATOR)) >= sizeof name)
+ return 0;
+ /* Look for the '@' separator. */
+ for (umark = id + ISAKMP_ID_DATA_OFF; (umark - id) < id_len;
+ umark++)
+ if (*umark == '@')
+ break;
+ if (*umark != '@') {
+ LOG_DBG((LOG_MISC, 50, "dns_get_key: bad UFQDN ID"));
+ return 0;
+ }
+ *umark++ = '\0';
+ /* id is now terminated. 'umark', however, is not. */
+ snprintf(name, sizeof name, "%s%s", id + ISAKMP_ID_DATA_OFF,
+ DNS_UFQDN_SEPARATOR);
+ memcpy(name + strlen(name), umark, id_len - strlen(id) - 1);
+ *(name + id_len + sizeof(DNS_UFQDN_SEPARATOR) - 2) = '.';
+ *(name + id_len + sizeof(DNS_UFQDN_SEPARATOR) - 1) = '\0';
+ break;
+
+ default:
+ return 0;
+ }
+
+ LOG_DBG((LOG_MISC, 50, "dns_get_key: trying KEY RR for %s", name));
+ ret = getrrsetbyname(name, C_IN, T_KEY, 0, &rr);
+
+ if (ret) {
+ LOG_DBG((LOG_MISC, 30, "dns_get_key: no DNS responses "
+ "(error %d)", ret));
+ return 0;
+ }
+ LOG_DBG((LOG_MISC, 80,
+ "dns_get_key: rrset class %d type %d ttl %d nrdatas %d nrsigs %d",
+ rr->rri_rdclass, rr->rri_rdtype, rr->rri_ttl, rr->rri_nrdatas,
+ rr->rri_nsigs));
+
+ /* We don't accept unvalidated data. */
+ if (!(rr->rri_flags & RRSET_VALIDATED)) {
+ LOG_DBG((LOG_MISC, 10, "dns_get_key: "
+ "got unvalidated response"));
+ freerrset(rr);
+ return 0;
+ }
+ /* Sanity. */
+ if (rr->rri_nrdatas == 0 || rr->rri_rdtype != T_KEY) {
+ LOG_DBG((LOG_MISC, 30, "dns_get_key: no KEY RRs received"));
+ freerrset(rr);
+ return 0;
+ }
+ memset(&key_rr, 0, sizeof key_rr);
+
+ /*
+ * Find a key with the wanted algorithm, if any.
+ * XXX If there are several keys present, we currently only find the
+ * first.
+ */
+ for (i = 0; i < rr->rri_nrdatas && key_rr.datalen == 0; i++) {
+ key_rr.flags = ntohs((u_int16_t) * rr->rri_rdatas[i].rdi_data);
+ key_rr.protocol = *(rr->rri_rdatas[i].rdi_data + 2);
+ key_rr.algorithm = *(rr->rri_rdatas[i].rdi_data + 3);
+
+ if (key_rr.protocol != DNS_KEYPROTO_IPSEC) {
+ LOG_DBG((LOG_MISC, 50, "dns_get_key: ignored "
+ "non-IPsec key"));
+ continue;
+ }
+ if (key_rr.algorithm != algorithm) {
+ LOG_DBG((LOG_MISC, 50, "dns_get_key: ignored "
+ "key with other alg"));
+ continue;
+ }
+ key_rr.datalen = rr->rri_rdatas[i].rdi_length - 4;
+ if (key_rr.datalen <= 0) {
+ LOG_DBG((LOG_MISC, 50, "dns_get_key: "
+ "ignored bad key"));
+ key_rr.datalen = 0;
+ continue;
+ }
+ /* This key seems to fit our requirements... */
+ key_rr.data = (char *)malloc(key_rr.datalen);
+ if (!key_rr.data) {
+ log_error("dns_get_key: malloc (%d) failed",
+ key_rr.datalen);
+ freerrset(rr);
+ return 0;
+ }
+ memcpy(key_rr.data, rr->rri_rdatas[i].rdi_data + 4,
+ key_rr.datalen);
+ *keylen = key_rr.datalen;
+ }
+
+ freerrset(rr);
+
+ if (key_rr.datalen)
+ return key_rr.data;
+ return 0;
+}
+
+int
+dns_RSA_dns_to_x509(u_int8_t *key, int keylen, RSA **rsa_key)
+{
+ RSA *rsa;
+ int key_offset;
+ u_int8_t e_len;
+
+ if (!key || keylen <= 0) {
+ log_print("dns_RSA_dns_to_x509: invalid public key");
+ return -1;
+ }
+ rsa = RSA_new();
+ if (rsa == NULL) {
+ log_error("dns_RSA_dns_to_x509: "
+ "failed to allocate new RSA struct");
+ return -1;
+ }
+ e_len = *key;
+ key_offset = 1;
+
+ if (e_len == 0) {
+ if (keylen < 3) {
+ log_print("dns_RSA_dns_to_x509: invalid public key");
+ RSA_free(rsa);
+ return -1;
+ }
+ e_len = *(key + key_offset++) << 8;
+ e_len += *(key + key_offset++);
+ }
+ if (e_len > (keylen - key_offset)) {
+ log_print("dns_RSA_dns_to_x509: invalid public key");
+ RSA_free(rsa);
+ return -1;
+ }
+ rsa->e = BN_bin2bn(key + key_offset, e_len, NULL);
+ key_offset += e_len;
+
+ /* XXX if (keylen <= key_offset) -> "invalid public key" ? */
+
+ rsa->n = BN_bin2bn(key + key_offset, keylen - key_offset, NULL);
+
+ *rsa_key = rsa;
+
+ LOG_DBG((LOG_MISC, 30, "dns_RSA_dns_to_x509: got %d bits RSA key",
+ BN_num_bits(rsa->n)));
+ return 0;
+}
+
+#if notyet
+int
+dns_RSA_x509_to_dns(RSA *rsa_key, u_int8_t *key, int *keylen)
+{
+ return 0;
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/dnssec.h b/keyexchange/isakmpd-20041012/dnssec.h
new file mode 100644
index 0000000..90a78df
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/dnssec.h
@@ -0,0 +1,46 @@
+/* $OpenBSD: dnssec.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */
+
+/*
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include "libcrypto.h"
+#include "message.h"
+
+void *dns_get_key(int, struct message *, int *);
+int dns_RSA_dns_to_x509(u_int8_t *, int, RSA **);
+
+#ifndef DNS_KEYALG_RSA
+#define DNS_KEYALG_RSA 1
+#endif
+
+#ifndef DNS_KEYPROTO_IPSEC
+#define DNS_KEYPROTO_IPSEC 4
+#endif
+#ifndef DNS_KEYALG_RSA
+#define DNS_KEYALG_RSA 1
+#endif
+
+#ifndef DNS_KEYPROTO_IPSEC
+#define DNS_KEYPROTO_IPSEC 4
+#endif
diff --git a/keyexchange/isakmpd-20041012/doi.c b/keyexchange/isakmpd-20041012/doi.c
new file mode 100644
index 0000000..e9a5030
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/doi.c
@@ -0,0 +1,61 @@
+/* $OpenBSD: doi.c,v 1.9 2004/07/09 16:06:48 deraadt Exp $ */
+/* $EOM: doi.c,v 1.4 1999/04/02 00:57:36 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+
+#include "sysdep.h"
+
+#include "doi.h"
+
+static
+LIST_HEAD(doi_list, doi) doi_tab;
+
+void
+doi_init(void)
+{
+ LIST_INIT(&doi_tab);
+}
+
+struct doi *
+doi_lookup(u_int8_t doi_id)
+{
+ struct doi *doi;
+
+ for (doi = LIST_FIRST(&doi_tab); doi && doi->id != doi_id;
+ doi = LIST_NEXT(doi, link));
+ return doi;
+}
+
+void
+doi_register(struct doi *doi)
+{
+ LIST_INSERT_HEAD(&doi_tab, doi, link);
+}
diff --git a/keyexchange/isakmpd-20041012/doi.h b/keyexchange/isakmpd-20041012/doi.h
new file mode 100644
index 0000000..f2bcc68
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/doi.h
@@ -0,0 +1,101 @@
+/* $OpenBSD: doi.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */
+/* $EOM: doi.h,v 1.29 2000/07/02 18:47:15 provos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _DOI_H_
+#define _DOI_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+struct exchange;
+struct keystate;
+struct message;
+struct payload;
+struct proto;
+struct sa;
+
+/* XXX This structure needs per-field commenting. */
+struct doi {
+ LIST_ENTRY(doi) link;
+ u_int8_t id;
+
+ /* Size of DOI-specific exchange data. */
+ size_t exchange_size;
+
+ /* Size of DOI-specific security association data. */
+ size_t sa_size;
+
+ /* Size of DOI-specific protocol data. */
+ size_t proto_size;
+
+#ifdef USE_DEBUG
+ int (*debug_attribute)(u_int16_t, u_int8_t *, u_int16_t,
+ void *);
+#endif
+ void (*delete_spi)(struct sa *, struct proto *, int);
+ int16_t *(*exchange_script)(u_int8_t);
+ void (*finalize_exchange)(struct message *);
+ void (*free_exchange_data)(void *);
+ void (*free_proto_data)(void *);
+ void (*free_sa_data)(void *);
+ struct keystate *(*get_keystate)(struct message *);
+ u_int8_t *(*get_spi)(size_t *, u_int8_t, struct message *);
+ int (*handle_leftover_payload)(struct message *, u_int8_t,
+ struct payload *);
+ int (*informational_post_hook)(struct message *);
+ int (*informational_pre_hook)(struct message *);
+ int (*is_attribute_incompatible)(u_int16_t, u_int8_t *,
+ u_int16_t, void *);
+ void (*proto_init)(struct proto *, char *);
+ void (*setup_situation)(u_int8_t *);
+ size_t (*situation_size)(void);
+ u_int8_t (*spi_size)(u_int8_t);
+ int (*validate_attribute)(u_int16_t, u_int8_t *,
+ u_int16_t, void *);
+ int (*validate_exchange)(u_int8_t);
+ int (*validate_id_information)(u_int8_t, u_int8_t *,
+ u_int8_t *, size_t, struct exchange *);
+ int (*validate_key_information)(u_int8_t *, size_t);
+ int (*validate_notification)(u_int16_t);
+ int (*validate_proto)(u_int8_t);
+ int (*validate_situation)(u_int8_t *, size_t *, size_t);
+ int (*validate_transform_id)(u_int8_t, u_int8_t);
+ int (*initiator)(struct message * msg);
+ int (*responder)(struct message * msg);
+ char *(*decode_ids)(char *, u_int8_t *, size_t, u_int8_t *,
+ size_t, int);
+};
+
+extern void doi_init(void);
+extern struct doi *doi_lookup(u_int8_t);
+extern void doi_register(struct doi *);
+
+#endif /* _DOI_H_ */
diff --git a/keyexchange/isakmpd-20041012/dpd.c b/keyexchange/isakmpd-20041012/dpd.c
new file mode 100644
index 0000000..4351637
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/dpd.c
@@ -0,0 +1,374 @@
+/* $OpenBSD: dpd.c,v 1.4 2004/08/10 15:59:10 ho Exp $ */
+
+/*
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "dpd.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ipsec.h"
+#include "isakmp_fld.h"
+#include "log.h"
+#include "message.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+
+/* From RFC 3706. */
+#define DPD_MAJOR 0x01
+#define DPD_MINOR 0x00
+#define DPD_SEQNO_SZ 4
+
+static const char dpd_vendor_id[] = {
+ 0xAF, 0xCA, 0xD7, 0x13, 0x68, 0xA1, 0xF1, /* RFC 3706 */
+ 0xC9, 0x6B, 0x86, 0x96, 0xFC, 0x77, 0x57,
+ DPD_MAJOR,
+ DPD_MINOR
+};
+
+#define DPD_RETRANS_MAX 5 /* max number of retries. */
+#define DPD_RETRANS_WAIT 5 /* seconds between retries. */
+
+/* DPD Timer State */
+enum dpd_tstate { DPD_TIMER_NORMAL, DPD_TIMER_CHECK };
+
+static void dpd_check_event(void *);
+static void dpd_event(void *);
+static u_int32_t dpd_timer_interval(u_int32_t);
+static void dpd_timer_reset(struct sa *, u_int32_t, enum dpd_tstate);
+
+/* Add the DPD VENDOR ID payload. */
+int
+dpd_add_vendor_payload(struct message *msg)
+{
+ u_int8_t *buf;
+ size_t buflen = sizeof dpd_vendor_id + ISAKMP_GEN_SZ;
+
+ buf = malloc(buflen);
+ if (!buf) {
+ log_error("dpd_add_vendor_payload: malloc(%lu) failed",
+ (unsigned long)buflen);
+ return -1;
+ }
+
+ SET_ISAKMP_GEN_LENGTH(buf, buflen);
+ memcpy(buf + ISAKMP_VENDOR_ID_OFF, dpd_vendor_id,
+ sizeof dpd_vendor_id);
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) {
+ free(buf);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Check an incoming message for DPD capability markers.
+ */
+void
+dpd_check_vendor_payload(struct message *msg, struct payload *p)
+{
+ u_int8_t *pbuf = p->p;
+ size_t vlen;
+
+ /* Already checked? */
+ if (msg->exchange->flags & EXCHANGE_FLAG_DPD_CAP_PEER) {
+ /* Just mark it as handled and return. */
+ p->flags |= PL_MARK;
+ return;
+ }
+
+ vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ;
+ if (vlen != sizeof dpd_vendor_id) {
+ LOG_DBG((LOG_EXCHANGE, 90,
+ "dpd_check_vendor_payload: bad size %d != %d", vlen,
+ sizeof dpd_vendor_id));
+ return;
+ }
+
+ if (memcmp(dpd_vendor_id, pbuf + ISAKMP_GEN_SZ, vlen) == 0) {
+ /* This peer is DPD capable. */
+ if (msg->isakmp_sa) {
+ msg->exchange->flags |= EXCHANGE_FLAG_DPD_CAP_PEER;
+ LOG_DBG((LOG_EXCHANGE, 10, "dpd_check_vendor_payload: "
+ "DPD capable peer detected"));
+ if (dpd_timer_interval(0) != 0) {
+ LOG_DBG((LOG_EXCHANGE, 10,
+ "dpd_check_vendor_payload: enabling"));
+ msg->isakmp_sa->flags |= SA_FLAG_DPD;
+ dpd_timer_reset(msg->isakmp_sa, 0,
+ DPD_TIMER_NORMAL);
+ }
+ }
+ p->flags |= PL_MARK;
+ }
+ return;
+}
+
+/*
+ * All incoming DPD Notify messages enter here. Message has been validated.
+ */
+void
+dpd_handle_notify(struct message *msg, struct payload *p)
+{
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ u_int16_t notify = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p);
+ u_int32_t p_seq;
+
+ /* Extract the sequence number. */
+ memcpy(&p_seq, p->p + ISAKMP_NOTIFY_SPI_OFF + ISAKMP_HDR_COOKIES_LEN,
+ sizeof p_seq);
+ p_seq = ntohl(p_seq);
+
+ LOG_DBG((LOG_MESSAGE, 40, "dpd_handle_notify: got %s seq %u",
+ constant_name(isakmp_notify_cst, notify), p_seq));
+
+ switch (notify) {
+ case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE:
+ /* The other peer wants to know we're alive. */
+ if (p_seq <= isakmp_sa->dpd_rseq) {
+ log_print("dpd_handle_notify: bad R_U_THERE seqno "
+ "%u <= %u", p_seq, isakmp_sa->dpd_rseq);
+ return;
+ }
+ isakmp_sa->dpd_rseq = p_seq;
+ message_send_dpd_notify(isakmp_sa,
+ ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK, p_seq);
+ break;
+
+ case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK:
+ /* This should be a response to a R_U_THERE we've sent. */
+ if (isakmp_sa->dpd_seq != p_seq) {
+ log_print("dpd_handle_notify: got bad ACK seqno %u, "
+ "expected %u", p_seq, isakmp_sa->dpd_seq);
+ /* XXX Give up? Retry? */
+ return;
+ }
+ break;
+ default:
+ ;
+ }
+
+ /* Mark handled. */
+ p->flags |= PL_MARK;
+
+ /* The other peer is alive, so we can safely wait a while longer. */
+ if (isakmp_sa->flags & SA_FLAG_DPD)
+ dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_NORMAL);
+}
+
+/* Calculate the time until next DPD exchange. */
+static u_int32_t
+dpd_timer_interval(u_int32_t offset)
+{
+ int32_t v = 0;
+
+#ifdef notyet
+ v = ...; /* XXX Per-peer specified DPD intervals? */
+#endif
+ if (!v)
+ v = conf_get_num("General", "DPD-check-interval", 0);
+ if (v < 1)
+ return 0; /* DPD-Check-Interval < 1 means disable DPD */
+
+ v -= offset;
+ return v < 1 ? 1 : v;
+}
+
+static void
+dpd_timer_reset(struct sa *sa, u_int32_t time_passed, enum dpd_tstate mode)
+{
+ struct timeval tv;
+
+ if (sa->dpd_event)
+ timer_remove_event(sa->dpd_event);
+
+ gettimeofday(&tv, 0);
+ switch (mode) {
+ case DPD_TIMER_NORMAL:
+ tv.tv_sec += dpd_timer_interval(time_passed);
+ sa->dpd_event = timer_add_event("dpd_event", dpd_event, sa,
+ &tv);
+ break;
+ case DPD_TIMER_CHECK:
+ tv.tv_sec += DPD_RETRANS_WAIT;
+ sa->dpd_event = timer_add_event("dpd_check_event",
+ dpd_check_event, sa, &tv);
+ break;
+ default:
+ ;
+ }
+ if (!sa->dpd_event)
+ log_print("dpd_timer_reset: timer_add_event failed");
+}
+
+/* Helper function for dpd_exchange_finalization(). */
+static int
+dpd_find_sa(struct sa *sa, void *v_sa)
+{
+ struct sa *isakmp_sa = v_sa;
+
+ return (sa->phase == 2 &&
+ memcmp(sa->id_i, isakmp_sa->id_i, sa->id_i_len) == 0 &&
+ memcmp(sa->id_r, isakmp_sa->id_r, sa->id_r_len) == 0);
+}
+
+struct dpd_args {
+ struct sa *isakmp_sa;
+ u_int32_t interval;
+};
+
+/* Helper function for dpd_event(). */
+static int
+dpd_check_time(struct sa *sa, void *v_arg)
+{
+ struct dpd_args *args = v_arg;
+ struct sockaddr *dst;
+ struct proto *proto;
+ struct sa_kinfo *ksa;
+ struct timeval tv;
+
+ if (sa->phase == 1 || (args->isakmp_sa->flags & SA_FLAG_DPD) == 0 ||
+ dpd_find_sa(sa, args->isakmp_sa) == 0)
+ return 0;
+
+ proto = TAILQ_FIRST(&sa->protos);
+ if (!proto || !proto->data)
+ return 0;
+ sa->transport->vtbl->get_src(sa->transport, &dst);
+
+ gettimeofday(&tv, 0);
+ ksa = sysdep_ipsec_get_kernel_sa(proto->spi[1], proto->spi_sz[1],
+ proto->proto, dst);
+
+ if (!ksa || !ksa->last_used)
+ return 0;
+
+ LOG_DBG((LOG_MESSAGE, 80, "dpd_check_time: "
+ "SA %p last use %u second(s) ago", sa,
+ (u_int32_t)(tv.tv_sec - ksa->last_used)));
+
+ if ((u_int32_t)(tv.tv_sec - ksa->last_used) < args->interval) {
+ args->interval = (u_int32_t)(tv.tv_sec - ksa->last_used);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Called by the timer. */
+static void
+dpd_event(void *v_sa)
+{
+ struct sa *isakmp_sa = v_sa;
+ struct dpd_args args;
+#if defined (USE_DEBUG)
+ struct sockaddr *dst;
+ char *addr;
+#endif
+
+ isakmp_sa->dpd_event = 0;
+
+ /* Check if there's been any incoming SA activity since last time. */
+ args.isakmp_sa = isakmp_sa;
+ args.interval = dpd_timer_interval(0);
+ if (sa_find(dpd_check_time, &args)) {
+ if (args.interval > dpd_timer_interval(0))
+ args.interval = 0;
+ dpd_timer_reset(isakmp_sa, args.interval, DPD_TIMER_NORMAL);
+ return;
+ }
+
+ /* No activity seen, do a DPD exchange. */
+ if (isakmp_sa->dpd_seq == 0) {
+ /*
+ * RFC 3706: first seq# should be random, with MSB zero,
+ * otherwise we just increment it.
+ */
+ getrandom((u_int8_t *)&isakmp_sa->dpd_seq,
+ sizeof isakmp_sa->dpd_seq);
+ isakmp_sa->dpd_seq &= 0x7FFF;
+ } else
+ isakmp_sa->dpd_seq++;
+
+#if defined (USE_DEBUG)
+ isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport, &dst);
+ if (sockaddr2text(dst, &addr, 0) == -1)
+ addr = 0;
+ LOG_DBG((LOG_MESSAGE, 30, "dpd_event: sending R_U_THERE to %s seq %u",
+ addr ? addr : "<unknown>", isakmp_sa->dpd_seq));
+ if (addr)
+ free(addr);
+#endif
+ message_send_dpd_notify(isakmp_sa, ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE,
+ isakmp_sa->dpd_seq);
+
+ /* And set the short timer. */
+ dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK);
+}
+
+/*
+ * Called by the timer. If this function is called, it means we did not
+ * recieve any R_U_THERE_ACK confirmation from the other peer.
+ */
+static void
+dpd_check_event(void *v_sa)
+{
+ struct sa *isakmp_sa = v_sa;
+ struct sa *sa;
+
+ isakmp_sa->dpd_event = 0;
+
+ if (++isakmp_sa->dpd_failcount < DPD_RETRANS_MAX) {
+ LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: "
+ "peer not responding, retry %u of %u",
+ isakmp_sa->dpd_failcount, DPD_RETRANS_MAX));
+ message_send_dpd_notify(isakmp_sa,
+ ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE, isakmp_sa->dpd_seq);
+ dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK);
+ return;
+ }
+
+ /*
+ * Peer is considered dead. Delete all SAs created under isakmp_sa.
+ */
+ LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: peer is dead, "
+ "deleting all SAs connected to SA %p", isakmp_sa));
+ while ((sa = sa_find(dpd_find_sa, isakmp_sa)) != 0) {
+ LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting SA %p",
+ sa));
+ sa_delete(sa, 0);
+ }
+ LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting ISAKMP SA %p",
+ isakmp_sa));
+ sa_delete(isakmp_sa, 0);
+}
diff --git a/keyexchange/isakmpd-20041012/dpd.h b/keyexchange/isakmpd-20041012/dpd.h
new file mode 100644
index 0000000..fa62c5b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/dpd.h
@@ -0,0 +1,38 @@
+/* $OpenBSD: dpd.h,v 1.2 2004/08/10 15:59:10 ho Exp $ */
+
+/*
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _DPD_H_
+#define _DPD_H_
+
+struct message;
+struct payload;
+struct sa;
+
+int dpd_add_vendor_payload(struct message *);
+void dpd_check_vendor_payload(struct message *, struct payload *);
+void dpd_handle_notify(struct message *, struct payload *);
+
+#endif /* _DPD_H_ */
diff --git a/keyexchange/isakmpd-20041012/exchange.c b/keyexchange/isakmpd-20041012/exchange.c
new file mode 100644
index 0000000..1c4ef1f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/exchange.c
@@ -0,0 +1,1799 @@
+/* $OpenBSD: exchange.c,v 1.104 2004/09/17 13:53:08 ho Exp $ */
+/* $EOM: exchange.c,v 1.143 2000/12/04 00:02:25 angelos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 1999, 2000, 2002 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "cert.h"
+#include "conf.h"
+#include "connection.h"
+#include "constants.h"
+#include "cookie.h"
+#include "crypto.h"
+#include "doi.h"
+#include "exchange.h"
+#include "ipsec_num.h"
+#include "isakmp.h"
+#ifdef USE_ISAKMP_CFG
+#include "isakmp_cfg.h"
+#endif
+#include "libcrypto.h"
+#include "log.h"
+#include "message.h"
+#include "timer.h"
+#include "transport.h"
+#include "ipsec.h"
+#include "sa.h"
+#include "util.h"
+#include "key.h"
+
+/* Initial number of bits from the cookies used as hash. */
+#define INITIAL_BUCKET_BITS 6
+
+/*
+ * Don't try to use more bits than this as a hash.
+ * We only XOR 16 bits so going above that means changing the code below
+ * too.
+ */
+#define MAX_BUCKET_BITS 16
+
+#ifdef USE_DEBUG
+static void exchange_dump(char *, struct exchange *);
+#endif
+static void exchange_free_aux(void *);
+#if 0
+static void exchange_resize(void);
+#endif
+static struct exchange *exchange_lookup_active(char *, int);
+
+static
+LIST_HEAD(exchange_list, exchange) *exchange_tab;
+
+/* Works both as a maximum index and a mask. */
+static int bucket_mask;
+
+/*
+ * Validation scripts used to test messages for correct content of
+ * payloads depending on the exchange type.
+ */
+int16_t script_base[] = {
+ ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_KEY_EXCH, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_KEY_EXCH, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_END
+};
+
+int16_t script_identity_protection[] = {
+ ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_KEY_EXCH, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_KEY_EXCH, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_ID, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_ID, /* Responder -> initiator. */
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_END
+};
+
+int16_t script_authentication_only[] = {
+ ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_NONCE,
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_ID, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_END
+};
+
+#ifdef USE_AGGRESSIVE
+int16_t script_aggressive[] = {
+ ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_KEY_EXCH,
+ ISAKMP_PAYLOAD_NONCE,
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_KEY_EXCH,
+ ISAKMP_PAYLOAD_NONCE,
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_SWITCH,
+ EXCHANGE_SCRIPT_AUTH, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_END
+};
+#endif /* USE_AGGRESSIVE */
+
+int16_t script_informational[] = {
+ EXCHANGE_SCRIPT_INFO, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_END
+};
+
+/*
+ * Check what exchange SA is negotiated with and return a suitable validation
+ * script.
+ */
+int16_t *
+exchange_script(struct exchange *exchange)
+{
+ switch (exchange->type) {
+ case ISAKMP_EXCH_BASE:
+ return script_base;
+ case ISAKMP_EXCH_ID_PROT:
+ return script_identity_protection;
+ case ISAKMP_EXCH_AUTH_ONLY:
+ return script_authentication_only;
+#ifdef USE_AGGRESSIVE
+ case ISAKMP_EXCH_AGGRESSIVE:
+ return script_aggressive;
+#endif
+ case ISAKMP_EXCH_INFO:
+ return script_informational;
+#ifdef USE_ISAKMP_CFG
+ case ISAKMP_EXCH_TRANSACTION:
+ return script_transaction;
+#endif
+ default:
+ if (exchange->type >= ISAKMP_EXCH_DOI_MIN &&
+ exchange->type <= ISAKMP_EXCH_DOI_MAX)
+ return exchange->doi->exchange_script(exchange->type);
+ }
+ return 0;
+}
+
+/*
+ * Validate the message MSG's contents wrt what payloads the exchange type
+ * requires at this point in the dialogoue. Return -1 if the validation fails,
+ * 0 if it succeeds and the script is not finished and 1 if it's ready.
+ */
+static int
+exchange_validate(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ int16_t *pc = exchange->exch_pc;
+
+ while (*pc != EXCHANGE_SCRIPT_END && *pc != EXCHANGE_SCRIPT_SWITCH) {
+ LOG_DBG((LOG_EXCHANGE, 90,
+ "exchange_validate: checking for required %s",
+ *pc >= ISAKMP_PAYLOAD_NONE
+ ? constant_name(isakmp_payload_cst, *pc)
+ : constant_name(exchange_script_cst, *pc)));
+
+ /* Check for existence of the required payloads. */
+ if ((*pc > 0 && !payload_first(msg, *pc))
+ || (*pc == EXCHANGE_SCRIPT_AUTH
+ && !payload_first(msg, ISAKMP_PAYLOAD_HASH)
+ && !payload_first(msg, ISAKMP_PAYLOAD_SIG))
+ || (*pc == EXCHANGE_SCRIPT_INFO
+ && ((!payload_first(msg, ISAKMP_PAYLOAD_NOTIFY)
+ && !payload_first(msg, ISAKMP_PAYLOAD_DELETE))
+ || (payload_first(msg, ISAKMP_PAYLOAD_DELETE)
+ && !payload_first(msg, ISAKMP_PAYLOAD_HASH))))) {
+ /* Missing payload. */
+ LOG_DBG((LOG_MESSAGE, 70,
+ "exchange_validate: msg %p requires missing %s",
+ msg, *pc >= ISAKMP_PAYLOAD_NONE
+ ? constant_name(isakmp_payload_cst, *pc)
+ : constant_name(exchange_script_cst, *pc)));
+ return -1;
+ }
+ pc++;
+ }
+ if (*pc == EXCHANGE_SCRIPT_END)
+ /* Cleanup. */
+ return 1;
+
+ return 0;
+}
+
+/* Feed unhandled payloads to the DOI for handling. Help for exchange_run(). */
+static void
+exchange_handle_leftover_payloads(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct doi *doi = exchange->doi;
+ struct payload *p;
+ int i;
+
+ for (i = ISAKMP_PAYLOAD_SA; i < payload_index_max; i++) {
+ if (i == ISAKMP_PAYLOAD_PROPOSAL ||
+ i == ISAKMP_PAYLOAD_TRANSFORM)
+ continue;
+ for (p = payload_first(msg, i); p;
+ p = TAILQ_NEXT(p, link)) {
+ if (p->flags & PL_MARK)
+ continue;
+ if (!doi->handle_leftover_payload ||
+ doi->handle_leftover_payload(msg, i, p))
+ LOG_DBG((LOG_EXCHANGE, 10,
+ "exchange_run: unexpected payload %s",
+ constant_name(isakmp_payload_cst, i)));
+ }
+ }
+}
+
+/*
+ * Run the exchange script from a point given by the "program counter"
+ * upto either the script's end or a transmittal of a message. If we are
+ * at the point of a reception of a message, that message should be handed
+ * in here in the MSG argument. Otherwise we are the initiator and should
+ * expect MSG to be a half-cooked message without payloads.
+ */
+void
+exchange_run(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct doi *doi = exchange->doi;
+ int (*handler)(struct message *) = exchange->initiator ?
+ doi->initiator : doi->responder;
+ int done = 0;
+
+ while (!done) {
+ /*
+ * It's our turn if we're either the initiator on an even step,
+ * or the responder on an odd step of the dialogue.
+ */
+ if (exchange->initiator ^ (exchange->step % 2)) {
+ done = 1;
+ if (exchange->step)
+ msg = message_alloc_reply(msg);
+ message_setup_header(msg, exchange->type, 0,
+ exchange->message_id);
+ if (handler(msg)) {
+ /*
+ * This can happen when transient starvation
+ * of memory occurs.
+ * XXX The peer's retransmit ought to
+ * kick-start this exchange again. If he's
+ * stopped retransmitting he's likely dropped
+ * the SA at his side so we need to do that
+ * too, i.e. implement automatic SA teardown
+ * after a certain amount of inactivity.
+ */
+ log_print("exchange_run: doi->%s (%p) failed",
+ exchange->initiator ? "initiator" :
+ "responder", msg);
+ message_free(msg);
+ return;
+ }
+ switch (exchange_validate(msg)) {
+ case 1:
+ /*
+ * The last message of a multi-message
+ * exchange should not be retransmitted other
+ * than "on-demand", i.e. if we see
+ * retransmits of the last message of the peer
+ * later.
+ */
+ msg->flags |= MSG_LAST;
+ if (exchange->step > 0) {
+ if (exchange->last_sent)
+ message_free(exchange->last_sent);
+ exchange->last_sent = msg;
+ }
+ /*
+ * After we physically have sent our last
+ * message we need to do SA-specific
+ * finalization, like telling our application
+ * the SA is ready to be used, or issuing a
+ * CONNECTED notify if we set the COMMIT bit.
+ */
+ message_register_post_send(msg,
+ exchange_finalize);
+
+ /* Fallthrough. */
+
+ case 0:
+ /* XXX error handling. */
+ message_send(msg);
+ break;
+
+ default:
+ log_print("exchange_run: exchange_validate "
+ "failed, DOI error");
+ exchange_free(exchange);
+ message_free(msg);
+ return;
+ }
+ } else {
+ done = exchange_validate(msg);
+ switch (done) {
+ case 0:
+ case 1:
+ /* Feed the message to the DOI. */
+ if (handler(msg)) {
+ /*
+ * Trust the peer to retransmit.
+ * XXX We have to implement SA aging
+ * with automatic teardown.
+ */
+ message_free(msg);
+ return;
+ }
+ /*
+ * Go over the yet unhandled payloads and feed
+ * them to DOI for handling.
+ */
+ exchange_handle_leftover_payloads(msg);
+
+ /*
+ * We have advanced the state. If we have
+ * been processing an incoming message, record
+ * that message as the one to do duplication
+ * tests against.
+ */
+ if (exchange->last_received)
+ message_free(exchange->last_received);
+ exchange->last_received = msg;
+ if (exchange->flags & EXCHANGE_FLAG_ENCRYPT)
+ crypto_update_iv(exchange->keystate);
+
+ if (done) {
+ exchange_finalize(msg);
+ return;
+ }
+ break;
+
+ case -1:
+ log_print("exchange_run: exchange_validate "
+ "failed");
+ /*
+ * XXX Is this the best error notification
+ * type?
+ */
+ message_drop(msg,
+ ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return;
+ }
+ }
+
+ LOG_DBG((LOG_EXCHANGE, 40,
+ "exchange_run: exchange %p finished step %d, advancing...",
+ exchange, exchange->step));
+ exchange->step++;
+ while (*exchange->exch_pc != EXCHANGE_SCRIPT_SWITCH
+ && *exchange->exch_pc != EXCHANGE_SCRIPT_END)
+ exchange->exch_pc++;
+ exchange->exch_pc++;
+ }
+}
+
+void
+exchange_init(void)
+{
+ int i;
+
+ bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1;
+ exchange_tab = malloc((bucket_mask + 1) *
+ sizeof(struct exchange_list));
+ if (!exchange_tab)
+ log_fatal("exchange_init: out of memory");
+ for (i = 0; i <= bucket_mask; i++)
+ LIST_INIT(&exchange_tab[i]);
+}
+
+#if 0
+/* XXX Currently unused. */
+static void
+exchange_resize(void)
+{
+ struct exchange_list *new_tab;
+ int new_mask = (bucket_mask + 1) * 2 - 1;
+ int i;
+
+ new_tab = realloc(exchange_tab,
+ (new_mask + 1) * sizeof(struct exchange_list));
+ if (!new_tab)
+ return;
+ for (i = bucket_mask + 1; i <= new_mask; i++)
+ LIST_INIT(&new_tab[i]);
+ bucket_mask = new_mask;
+ /* XXX Rehash existing entries. */
+}
+#endif
+
+/* Lookup a phase 1 exchange out of just the initiator cookie. */
+struct exchange *
+exchange_lookup_from_icookie(u_int8_t * cookie)
+{
+ struct exchange *exchange;
+ int i;
+
+ for (i = 0; i <= bucket_mask; i++)
+ for (exchange = LIST_FIRST(&exchange_tab[i]); exchange;
+ exchange = LIST_NEXT(exchange, link))
+ if (memcmp(exchange->cookies, cookie,
+ ISAKMP_HDR_ICOOKIE_LEN) == 0 &&
+ exchange->phase == 1)
+ return exchange;
+ return 0;
+}
+
+/* Lookup an exchange out of the name and phase. */
+struct exchange *
+exchange_lookup_by_name(char *name, int phase)
+{
+ struct exchange *exchange;
+ int i;
+
+ /* If we search for nothing, we will find nothing. */
+ if (!name)
+ return 0;
+
+ for (i = 0; i <= bucket_mask; i++)
+ for (exchange = LIST_FIRST(&exchange_tab[i]); exchange;
+ exchange = LIST_NEXT(exchange, link)) {
+ LOG_DBG((LOG_EXCHANGE, 90,
+ "exchange_lookup_by_name: %s == %s && %d == %d?",
+ name, exchange->name ? exchange->name :
+ "<unnamed>", phase, exchange->phase));
+
+ /*
+ * Match by name, but don't select finished exchanges,
+ * i.e where MSG_LAST are set in last_sent msg.
+ */
+ if (exchange->name &&
+ strcasecmp(exchange->name, name) == 0 &&
+ exchange->phase == phase &&
+ (!exchange->last_sent ||
+ (exchange->last_sent->flags & MSG_LAST) == 0))
+ return exchange;
+ }
+ return 0;
+}
+
+/* Lookup an exchange out of the name, phase and step > 1. */
+static struct exchange *
+exchange_lookup_active(char *name, int phase)
+{
+ struct exchange *exchange;
+ int i;
+
+ /* XXX Almost identical to exchange_lookup_by_name. */
+
+ if (!name)
+ return 0;
+
+ for (i = 0; i <= bucket_mask; i++)
+ for (exchange = LIST_FIRST(&exchange_tab[i]); exchange;
+ exchange = LIST_NEXT(exchange, link)) {
+ LOG_DBG((LOG_EXCHANGE, 90,
+ "exchange_lookup_active: %s == %s && %d == %d?",
+ name, exchange->name ? exchange->name :
+ "<unnamed>", phase, exchange->phase));
+ if (exchange->name &&
+ strcasecmp(exchange->name, name) == 0 &&
+ exchange->phase == phase) {
+ if (exchange->step > 1)
+ return exchange;
+ else
+ LOG_DBG((LOG_EXCHANGE, 80,
+ "exchange_lookup_active: avoided "
+ "early (pre-step 1) exchange %p",
+ exchange));
+ }
+ }
+ return 0;
+}
+
+static void
+exchange_enter(struct exchange *exchange)
+{
+ u_int16_t bucket = 0;
+ u_int8_t *cp;
+ int i;
+
+ /* XXX We might resize if we are crossing a certain threshold */
+
+ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2) {
+ cp = exchange->cookies + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2) {
+ cp = exchange->message_id + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ bucket &= bucket_mask;
+ LIST_INSERT_HEAD(&exchange_tab[bucket], exchange, link);
+}
+
+/*
+ * Lookup the exchange given by the header fields MSG. PHASE2 is false when
+ * looking for phase 1 exchanges and true otherwise.
+ */
+struct exchange *
+exchange_lookup(u_int8_t *msg, int phase2)
+{
+ struct exchange *exchange;
+ u_int16_t bucket = 0;
+ u_int8_t *cp;
+ int i;
+
+ /*
+ * We use the cookies to get bits to use as an index into exchange_tab,
+ * as at least one (our cookie) is a good hash, xoring all the bits,
+ * 16 at a time, and then masking, should do. Doing it this way means
+ * we can validate cookies very fast thus delimiting the effects of
+ * "Denial of service"-attacks using packet flooding.
+ */
+ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2) {
+ cp = msg + ISAKMP_HDR_COOKIES_OFF + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ if (phase2)
+ for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2) {
+ cp = msg + ISAKMP_HDR_MESSAGE_ID_OFF + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ bucket &= bucket_mask;
+ for (exchange = LIST_FIRST(&exchange_tab[bucket]);
+ exchange && (memcmp(msg + ISAKMP_HDR_COOKIES_OFF,
+ exchange->cookies, ISAKMP_HDR_COOKIES_LEN) != 0 ||
+ (phase2 && memcmp(msg + ISAKMP_HDR_MESSAGE_ID_OFF,
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN) != 0) ||
+ (!phase2 && !zero_test(msg + ISAKMP_HDR_MESSAGE_ID_OFF,
+ ISAKMP_HDR_MESSAGE_ID_LEN)));
+ exchange = LIST_NEXT(exchange, link))
+ ;
+
+ return exchange;
+}
+
+/*
+ * Create a phase PHASE exchange where INITIATOR denotes our role. DOI
+ * is the domain of interpretation identifier and TYPE tells what exchange
+ * type to use per either the DOI document or the ISAKMP spec proper.
+ * NSA tells how many SAs we should pre-allocate, and should be zero
+ * when we have the responder role.
+ */
+static struct exchange *
+exchange_create(int phase, int initiator, int doi, int type)
+{
+ struct exchange *exchange;
+ struct timeval expiration;
+ int delta;
+
+ /*
+ * We want the exchange zeroed for exchange_free to be able to find
+ * out what fields have been filled-in.
+ */
+ exchange = calloc(1, sizeof *exchange);
+ if (!exchange) {
+ log_error("exchange_create: calloc (1, %lu) failed",
+ (unsigned long)sizeof *exchange);
+ return 0;
+ }
+ exchange->phase = phase;
+ exchange->step = 0;
+ exchange->initiator = initiator;
+ memset(exchange->cookies, 0, ISAKMP_HDR_COOKIES_LEN);
+ memset(exchange->message_id, 0, ISAKMP_HDR_MESSAGE_ID_LEN);
+ exchange->doi = doi_lookup(doi);
+ exchange->type = type;
+ exchange->policy_id = -1;
+ exchange->exch_pc = exchange_script(exchange);
+ exchange->last_sent = exchange->last_received = 0;
+ TAILQ_INIT(&exchange->sa_list);
+ TAILQ_INIT(&exchange->aca_list);
+
+ /* Allocate the DOI-specific structure and initialize it to zeroes. */
+ if (exchange->doi->exchange_size) {
+ exchange->data = calloc(1, exchange->doi->exchange_size);
+ if (!exchange->data) {
+ log_error("exchange_create: calloc (1, %lu) failed",
+ (unsigned long)exchange->doi->exchange_size);
+ exchange_free(exchange);
+ return 0;
+ }
+ }
+ gettimeofday(&expiration, 0);
+ delta = conf_get_num("General", "Exchange-max-time",
+ EXCHANGE_MAX_TIME);
+ expiration.tv_sec += delta;
+ exchange->death = timer_add_event("exchange_free_aux",
+ exchange_free_aux, exchange, &expiration);
+ if (!exchange->death) {
+ /* If we don't give up we might start leaking... */
+ exchange_free_aux(exchange);
+ return 0;
+ }
+ return exchange;
+}
+
+struct exchange_finalization_node {
+ void (*first)(struct exchange *, void *, int);
+ void *first_arg;
+ void (*second)(struct exchange *, void *, int);
+ void *second_arg;
+};
+
+/* Run the finalization functions of ARG. */
+static void
+exchange_run_finalizations(struct exchange *exchange, void *arg, int fail)
+{
+ struct exchange_finalization_node *node = arg;
+
+ node->first(exchange, node->first_arg, fail);
+ node->second(exchange, node->second_arg, fail);
+ free(node);
+}
+
+/*
+ * Add a finalization function FINALIZE with argument ARG to the tail
+ * of the finalization function list of EXCHANGE.
+ */
+static void
+exchange_add_finalization(struct exchange *exchange,
+ void (*finalize)(struct exchange *, void *, int), void *arg)
+{
+ struct exchange_finalization_node *node;
+
+ if (!finalize)
+ return;
+
+ if (!exchange->finalize) {
+ exchange->finalize = finalize;
+ exchange->finalize_arg = arg;
+ return;
+ }
+ node = malloc(sizeof *node);
+ if (!node) {
+ log_error("exchange_add_finalization: malloc (%lu) failed",
+ (unsigned long)sizeof *node);
+ free(arg);
+ return;
+ }
+ node->first = exchange->finalize;
+ node->first_arg = exchange->finalize_arg;
+ node->second = finalize;
+ node->second_arg = arg;
+ exchange->finalize = exchange_run_finalizations;
+ exchange->finalize_arg = node;
+}
+
+#ifdef USE_ISAKMP_CFG
+static void
+exchange_establish_transaction(struct exchange *exchange, void *arg, int fail)
+{
+ /* Establish a TRANSACTION exchange. */
+ struct exchange_finalization_node *node =
+ (struct exchange_finalization_node *)arg;
+ struct sa *isakmp_sa = sa_lookup_by_name((char *) node->second_arg, 1);
+
+ if (isakmp_sa && !fail)
+ exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_TRANSACTION, 0, 0,
+ node->first, node->first_arg);
+
+ free(node);
+}
+#endif /* USE_ISAKMP_CFG */
+
+/* Establish a phase 1 exchange. */
+void
+exchange_establish_p1(struct transport *t, u_int8_t type, u_int32_t doi,
+ char *name, void *args, void (*finalize)(struct exchange *, void *, int),
+ void *arg)
+{
+ struct exchange *exchange;
+ struct message *msg;
+#ifdef USE_ISAKMP_CFG
+ struct conf_list *flags;
+ struct conf_list_node *flag;
+#endif
+ char *tag = 0;
+ char *str;
+
+ if (name) {
+ /* If no exchange type given, fetch from the configuration. */
+ if (type == 0) {
+ /*
+ * XXX Similar code can be found in
+ * exchange_setup_p1. Share?
+ */
+
+ /* Find out our phase 1 mode. */
+ tag = conf_get_str(name, "Configuration");
+ if (!tag) {
+ /* Use default setting. */
+ tag = CONF_DFLT_TAG_PHASE1_CONFIG;
+ }
+ /* Figure out the DOI. XXX Factor out? */
+ str = conf_get_str(tag, "DOI");
+ if (!str || strcasecmp(str, "IPSEC") == 0)
+ doi = IPSEC_DOI_IPSEC;
+ else if (strcasecmp(str, "ISAKMP") == 0)
+ doi = ISAKMP_DOI_ISAKMP;
+ else {
+ log_print("exchange_establish_p1: "
+ "DOI \"%s\" unsupported", str);
+ return;
+ }
+
+ /* What exchange type do we want? */
+ str = conf_get_str(tag, "EXCHANGE_TYPE");
+ if (!str) {
+ log_print("exchange_establish_p1: "
+ "no \"EXCHANGE_TYPE\" tag in [%s] section",
+ tag);
+ return;
+ }
+ type = constant_value(isakmp_exch_cst, str);
+ if (!type) {
+ log_print("exchange_setup_p1: "
+ "unknown exchange type %s", str);
+ return;
+ }
+ }
+ }
+ exchange = exchange_create(1, 1, doi, type);
+ if (!exchange) {
+ /* XXX Do something here? */
+ return;
+ }
+ if (name) {
+ exchange->name = strdup(name);
+ if (!exchange->name) {
+ log_error("exchange_establish_p1: "
+ "strdup (\"%s\") failed", name);
+ exchange_free(exchange);
+ return;
+ }
+ }
+ exchange->policy = name ? conf_get_str(name, "Configuration") : 0;
+ if (!exchange->policy && name)
+ exchange->policy = CONF_DFLT_TAG_PHASE1_CONFIG;
+
+#ifdef USE_ISAKMP_CFG
+ if (name && (flags = conf_get_list(name, "Flags")) != NULL) {
+ for (flag = TAILQ_FIRST(&flags->fields); flag;
+ flag = TAILQ_NEXT(flag, link))
+ if (strcasecmp(flag->field, "ikecfg") == 0) {
+ struct exchange_finalization_node *node;
+
+ node = calloc(1, (unsigned long)sizeof *node);
+ if (!node) {
+ log_print("exchange_establish_p1: "
+ "calloc (1, %lu) failed",
+ (unsigned long)sizeof(*node));
+ exchange_free(exchange);
+ return;
+ }
+ /*
+ * Insert this finalization inbetween
+ * the original.
+ */
+ node->first = finalize;
+ node->first_arg = arg;
+ node->second_arg = name;
+ exchange_add_finalization(exchange,
+ exchange_establish_transaction,
+ node);
+ finalize = 0;
+ }
+ conf_free_list(flags);
+ }
+#endif /* USE_ISAKMP_CFG */
+
+ exchange_add_finalization(exchange, finalize, arg);
+ cookie_gen(t, exchange, exchange->cookies, ISAKMP_HDR_ICOOKIE_LEN);
+ exchange_enter(exchange);
+#ifdef USE_DEBUG
+ exchange_dump("exchange_establish_p1", exchange);
+#endif
+
+ msg = message_alloc(t, 0, ISAKMP_HDR_SZ);
+ if (!msg) {
+ log_print("exchange_establish_p1: message_alloc () failed");
+ exchange_free(exchange);
+ return;
+ }
+ msg->exchange = exchange;
+
+ /* Do not create SA for an information or transaction exchange. */
+ if (exchange->type != ISAKMP_EXCH_INFO
+ && exchange->type != ISAKMP_EXCH_TRANSACTION) {
+ /*
+ * Don't install a transport into this SA as it will be an
+ * INADDR_ANY address in the local end, which is not good at
+ * all. Let the reply packet install the transport instead.
+ */
+ sa_create(exchange, 0);
+ msg->isakmp_sa = TAILQ_FIRST(&exchange->sa_list);
+ if (!msg->isakmp_sa) {
+ /* XXX Do something more here? */
+ message_free(msg);
+ exchange_free(exchange);
+ return;
+ }
+ sa_reference(msg->isakmp_sa);
+ }
+ msg->extra = args;
+
+ exchange_run(msg);
+}
+
+/* Establish a phase 2 exchange. XXX With just one SA for now. */
+void
+exchange_establish_p2(struct sa *isakmp_sa, u_int8_t type, char *name,
+ void *args, void (*finalize)(struct exchange *, void *, int), void *arg)
+{
+ struct exchange *exchange;
+ struct message *msg;
+ u_int32_t doi = ISAKMP_DOI_ISAKMP;
+ u_int32_t seq = 0;
+ int i;
+ char *tag, *str;
+
+ if (isakmp_sa)
+ doi = isakmp_sa->doi->id;
+
+ if (name) {
+ /* Find out our phase 2 modes. */
+ tag = conf_get_str(name, "Configuration");
+ if (!tag) {
+ log_print("exchange_establish_p2: "
+ "no configuration for peer \"%s\"", name);
+ return;
+ }
+ seq = (u_int32_t)conf_get_num(name, "Acquire-ID", 0);
+
+ /* Figure out the DOI. */
+ str = conf_get_str(tag, "DOI");
+ if (!str || strcasecmp(str, "IPSEC") == 0)
+ doi = IPSEC_DOI_IPSEC;
+ else if (strcasecmp(str, "ISAKMP") == 0)
+ doi = ISAKMP_DOI_ISAKMP;
+ else {
+ log_print("exchange_establish_p2: "
+ "DOI \"%s\" unsupported", str);
+ return;
+ }
+
+ /* What exchange type do we want? */
+ if (!type) {
+ str = conf_get_str(tag, "EXCHANGE_TYPE");
+ if (!str) {
+ log_print("exchange_establish_p2: "
+ "no \"EXCHANGE_TYPE\" tag in [%s] section",
+ tag);
+ return;
+ }
+ /* XXX IKE dependent. */
+ type = constant_value(ike_exch_cst, str);
+ if (!type) {
+ log_print("exchange_establish_p2: unknown "
+ "exchange type %s", str);
+ return;
+ }
+ }
+ }
+ exchange = exchange_create(2, 1, doi, type);
+ if (!exchange) {
+ /* XXX Do something here? */
+ return;
+ }
+ if (name) {
+ exchange->name = strdup(name);
+ if (!exchange->name) {
+ log_error("exchange_establish_p2: "
+ "strdup (\"%s\") failed", name);
+ exchange_free(exchange);
+ return;
+ }
+ }
+ exchange->policy = name ? conf_get_str(name, "Configuration") : 0;
+ exchange->finalize = finalize;
+ exchange->finalize_arg = arg;
+ exchange->seq = seq;
+ memcpy(exchange->cookies, isakmp_sa->cookies, ISAKMP_HDR_COOKIES_LEN);
+ getrandom(exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+#if defined (USE_NAT_TRAVERSAL)
+ if (isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE)
+ exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
+ if (isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE)
+ exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE;
+#endif
+ exchange_enter(exchange);
+#ifdef USE_DEBUG
+ exchange_dump("exchange_establish_p2", exchange);
+#endif
+
+ /*
+ * Do not create SA's for informational exchanges.
+ * XXX How to handle new group mode?
+ */
+ if (exchange->type != ISAKMP_EXCH_INFO &&
+ exchange->type != ISAKMP_EXCH_TRANSACTION) {
+ /* XXX Number of SAs should come from the args structure. */
+ for (i = 0; i < 1; i++)
+ if (sa_create(exchange, isakmp_sa->transport)) {
+ exchange_free(exchange);
+ return;
+ }
+ }
+ msg = message_alloc(isakmp_sa->transport, 0, ISAKMP_HDR_SZ);
+ msg->isakmp_sa = isakmp_sa;
+ sa_reference(isakmp_sa);
+
+ msg->extra = args;
+
+ /* This needs to be done late or else get_keystate won't work right. */
+ msg->exchange = exchange;
+
+ exchange_run(msg);
+}
+
+/* Out of an incoming phase 1 message, setup an exchange. */
+struct exchange *
+exchange_setup_p1(struct message *msg, u_int32_t doi)
+{
+ struct transport *t = msg->transport;
+ struct exchange *exchange;
+ struct sockaddr *dst;
+#ifdef USE_ISAKMP_CFG
+ struct conf_list *flags;
+ struct conf_list_node *flag;
+#endif
+ char *name = 0, *policy = 0, *str;
+ u_int32_t want_doi;
+ u_int8_t type;
+
+ /* XXX Similar code can be found in exchange_establish_p1. Share? */
+
+ /*
+ * Unless this is an informational exchange, look up our policy for
+ * this peer.
+ */
+ type = GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base);
+ if (type != ISAKMP_EXCH_INFO) {
+ /*
+ * Find out our inbound phase 1 mode.
+ */
+ t->vtbl->get_dst(t, &dst);
+ if (sockaddr2text(dst, &str, 0) == -1)
+ return 0;
+ name = conf_get_str("Phase 1", str);
+ free(str);
+ if (name) {
+ /*
+ * If another phase 1 exchange is ongoing don't bother
+ * returning the call. However, we will need to
+ * continue responding if our phase 1 exchange is
+ * still waiting for step 1 (i.e still half-open).
+ */
+ if (exchange_lookup_active(name, 1))
+ return 0;
+ } else {
+ name = conf_get_str("Phase 1", "Default");
+ if (!name) {
+ log_print("exchange_setup_p1: no \"Default\" "
+ "tag in [Phase 1] section");
+ return 0;
+ }
+ }
+
+ policy = conf_get_str(name, "Configuration");
+ if (!policy)
+ policy = CONF_DFLT_TAG_PHASE1_CONFIG;
+
+ /* Figure out the DOI. */
+ str = conf_get_str(policy, "DOI");
+ if (!str || strcasecmp(str, "IPSEC") == 0)
+ want_doi = IPSEC_DOI_IPSEC;
+ else if (strcasecmp(str, "ISAKMP") == 0)
+ want_doi = ISAKMP_DOI_ISAKMP;
+ else {
+ log_print("exchange_setup_p1: "
+ "DOI \"%s\" unsupported", str);
+ return 0;
+ }
+ if (want_doi != doi) {
+ /* XXX Should I tell what DOI I got? */
+ log_print("exchange_setup_p1: expected %s DOI", str);
+ return 0;
+ }
+ /* What exchange type do we want? */
+ str = conf_get_str(policy, "EXCHANGE_TYPE");
+ if (!str) {
+ log_print("exchange_setup_p1: no \"EXCHANGE_TYPE\" "
+ "tag in [%s] section", policy);
+ return 0;
+ }
+ type = constant_value(isakmp_exch_cst, str);
+ if (!type) {
+ log_print("exchange_setup_p1: "
+ "unknown exchange type %s", str);
+ return 0;
+ }
+ if (type != GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base)) {
+ log_print("exchange_setup_p1: "
+ "expected exchange type %s got %s", str,
+ constant_name(isakmp_exch_cst,
+ GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base)));
+ return 0;
+ }
+ }
+ exchange = exchange_create(1, 0, doi, type);
+ if (!exchange)
+ return 0;
+
+ exchange->name = name ? strdup(name) : 0;
+ if (name && !exchange->name) {
+ log_error("exchange_setup_p1: strdup (\"%s\") failed", name);
+ exchange_free(exchange);
+ return 0;
+ }
+ exchange->policy = policy;
+
+#ifdef USE_ISAKMP_CFG
+ if (name && (flags = conf_get_list(name, "Flags")) != NULL) {
+ for (flag = TAILQ_FIRST(&flags->fields); flag;
+ flag = TAILQ_NEXT(flag, link))
+ if (strcasecmp(flag->field, "ikecfg") == 0) {
+ struct exchange_finalization_node *node;
+
+ node = calloc(1, (unsigned long)sizeof *node);
+ if (!node) {
+ log_print("exchange_establish_p1: "
+ "calloc (1, %lu) failed",
+ (unsigned long)sizeof(*node));
+ exchange_free(exchange);
+ return 0;
+ }
+ /*
+ * Insert this finalization inbetween
+ * the original.
+ */
+ node->first = 0;
+ node->first_arg = 0;
+ node->second_arg = name;
+ exchange_add_finalization(exchange,
+ exchange_establish_transaction,
+ node);
+ }
+ conf_free_list(flags);
+ }
+#endif
+
+ cookie_gen(msg->transport, exchange, exchange->cookies +
+ ISAKMP_HDR_ICOOKIE_LEN, ISAKMP_HDR_RCOOKIE_LEN);
+ GET_ISAKMP_HDR_ICOOKIE(msg->iov[0].iov_base, exchange->cookies);
+ exchange_enter(exchange);
+#ifdef USE_DEBUG
+ exchange_dump("exchange_setup_p1", exchange);
+#endif
+ return exchange;
+}
+
+/* Out of an incoming phase 2 message, setup an exchange. */
+struct exchange *
+exchange_setup_p2(struct message *msg, u_int8_t doi)
+{
+ struct exchange *exchange;
+ u_int8_t *buf = msg->iov[0].iov_base;
+
+ exchange = exchange_create(2, 0, doi, GET_ISAKMP_HDR_EXCH_TYPE(buf));
+ if (!exchange)
+ return 0;
+ GET_ISAKMP_HDR_ICOOKIE(buf, exchange->cookies);
+ GET_ISAKMP_HDR_RCOOKIE(buf,
+ exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN);
+ GET_ISAKMP_HDR_MESSAGE_ID(buf, exchange->message_id);
+#if defined (USE_NAT_TRAVERSAL)
+ if (msg->isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE)
+ exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
+ if (msg->isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE)
+ exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE;
+#endif
+ exchange_enter(exchange);
+#ifdef USE_DEBUG
+ exchange_dump("exchange_setup_p2", exchange);
+#endif
+ return exchange;
+}
+
+/* Dump interesting data about an exchange. */
+static void
+exchange_dump_real(char *header, struct exchange *exchange, int class,
+ int level)
+{
+ struct sa *sa;
+ char buf[LOG_SIZE];
+ /* Don't risk overflowing the final log buffer. */
+ size_t bufsize_max = LOG_SIZE - strlen(header) - 32;
+
+ LOG_DBG((class, level,
+ "%s: %p %s %s policy %s phase %d doi %d exchange %d step %d",
+ header, exchange, exchange->name ? exchange->name : "<unnamed>",
+ exchange->policy ? exchange->policy : "<no policy>",
+ exchange->initiator ? "initiator" : "responder", exchange->phase,
+ exchange->doi->id, exchange->type, exchange->step));
+ LOG_DBG((class, level, "%s: icookie %08x%08x rcookie %08x%08x", header,
+ decode_32(exchange->cookies), decode_32(exchange->cookies + 4),
+ decode_32(exchange->cookies + 8),
+ decode_32(exchange->cookies + 12)));
+
+ /* Include phase 2 SA list for this exchange */
+ if (exchange->phase == 2) {
+ snprintf(buf, bufsize_max, "sa_list ");
+ for (sa = TAILQ_FIRST(&exchange->sa_list);
+ sa && strlen(buf) < bufsize_max; sa = TAILQ_NEXT(sa, next))
+ snprintf(buf + strlen(buf), bufsize_max - strlen(buf),
+ "%p ", sa);
+ if (sa)
+ strlcat(buf, "...", bufsize_max);
+ } else
+ buf[0] = '\0';
+
+ LOG_DBG((class, level, "%s: msgid %08x %s", header,
+ decode_32(exchange->message_id), buf));
+}
+
+#ifdef USE_DEBUG
+static void
+exchange_dump(char *header, struct exchange *exchange)
+{
+ exchange_dump_real(header, exchange, LOG_EXCHANGE, 10);
+}
+#endif
+
+void
+exchange_report(void)
+{
+ struct exchange *exchange;
+ int i;
+
+ for (i = 0; i <= bucket_mask; i++)
+ for (exchange = LIST_FIRST(&exchange_tab[i]); exchange;
+ exchange = LIST_NEXT(exchange, link))
+ exchange_dump_real("exchange_report", exchange,
+ LOG_REPORT, 0);
+}
+
+/*
+ * Release all resources this exchange is using *except* for the "death"
+ * event. When removing an exchange from the expiration handler that event
+ * will be dealt with therein instead.
+ */
+static void
+exchange_free_aux(void *v_exch)
+{
+ struct exchange *exchange = v_exch;
+ struct sa *sa, *next_sa;
+ struct cert_handler *handler;
+
+ LOG_DBG((LOG_EXCHANGE, 80, "exchange_free_aux: freeing exchange %p",
+ exchange));
+
+ if (exchange->last_received)
+ message_free(exchange->last_received);
+ if (exchange->last_sent)
+ message_free(exchange->last_sent);
+ if (exchange->in_transit &&
+ exchange->in_transit != exchange->last_sent)
+ message_free(exchange->in_transit);
+ if (exchange->nonce_i)
+ free(exchange->nonce_i);
+ if (exchange->nonce_r)
+ free(exchange->nonce_r);
+ if (exchange->id_i)
+ free(exchange->id_i);
+ if (exchange->id_r)
+ free(exchange->id_r);
+ if (exchange->keystate)
+ free(exchange->keystate);
+ if (exchange->doi && exchange->doi->free_exchange_data)
+ exchange->doi->free_exchange_data(exchange->data);
+ if (exchange->data)
+ free(exchange->data);
+ if (exchange->name)
+ free(exchange->name);
+ if (exchange->recv_cert) {
+ handler = cert_get(exchange->recv_certtype);
+ if (handler)
+ handler->cert_free(exchange->recv_cert);
+ }
+ if (exchange->sent_cert) {
+ handler = cert_get(exchange->sent_certtype);
+ if (handler)
+ handler->cert_free(exchange->sent_cert);
+ }
+ if (exchange->recv_key)
+ key_free(exchange->recv_keytype, ISAKMP_KEYTYPE_PUBLIC,
+ exchange->recv_key);
+ if (exchange->keynote_key)
+ free(exchange->keynote_key); /* This is just a string */
+
+#if defined (POLICY) || defined (KEYNOTE)
+ if (exchange->policy_id != -1)
+ kn_close(exchange->policy_id);
+#endif
+
+ exchange_free_aca_list(exchange);
+ LIST_REMOVE(exchange, link);
+
+ /* Tell potential finalize routine we never got there. */
+ if (exchange->finalize)
+ exchange->finalize(exchange, exchange->finalize_arg, 1);
+
+ /* Remove any SAs that have not been disassociated from us. */
+ for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = next_sa) {
+ next_sa = TAILQ_NEXT(sa, next);
+ /* One for the reference in exchange->sa_list. */
+ sa_release(sa);
+ /* And two more for the expiration and SA linked list. */
+ sa_free(sa);
+ }
+
+ free(exchange);
+}
+
+/* Release all resources this exchange is using. */
+void
+exchange_free(struct exchange *exchange)
+{
+ if (exchange->death)
+ timer_remove_event(exchange->death);
+ exchange_free_aux(exchange);
+}
+
+/*
+ * Upgrade the phase 1 exchange and its ISAKMP SA with the rcookie of our
+ * peer (found in his recently sent message MSG).
+ */
+void
+exchange_upgrade_p1(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+
+ LIST_REMOVE(exchange, link);
+ GET_ISAKMP_HDR_RCOOKIE(msg->iov[0].iov_base, exchange->cookies +
+ ISAKMP_HDR_ICOOKIE_LEN);
+ exchange_enter(exchange);
+ sa_isakmp_upgrade(msg);
+}
+
+static int
+exchange_check_old_sa(struct sa *sa, void *v_arg)
+{
+ struct sa *new_sa = v_arg;
+ char res1[1024];
+
+ if (sa == new_sa || !sa->name || !(sa->flags & SA_FLAG_READY) ||
+ (sa->flags & SA_FLAG_REPLACED))
+ return 0;
+
+ if (sa->phase != new_sa->phase || new_sa->name == 0 ||
+ strcasecmp(sa->name, new_sa->name))
+ return 0;
+
+ if (sa->initiator)
+ strlcpy(res1, ipsec_decode_ids("%s %s", sa->id_i, sa->id_i_len,
+ sa->id_r, sa->id_r_len, 0), sizeof res1);
+ else
+ strlcpy(res1, ipsec_decode_ids("%s %s", sa->id_r, sa->id_r_len,
+ sa->id_i, sa->id_i_len, 0), sizeof res1);
+
+ LOG_DBG((LOG_EXCHANGE, 30,
+ "checking whether new SA replaces existing SA with IDs %s", res1));
+
+ if (new_sa->initiator)
+ return strcasecmp(res1, ipsec_decode_ids("%s %s", new_sa->id_i,
+ new_sa->id_i_len, new_sa->id_r, new_sa->id_r_len, 0)) == 0;
+ else
+ return strcasecmp(res1, ipsec_decode_ids("%s %s", new_sa->id_r,
+ new_sa->id_r_len, new_sa->id_i, new_sa->id_i_len, 0)) == 0;
+}
+
+void
+exchange_finalize(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct sa *sa, *old_sa;
+ struct proto *proto;
+ struct conf_list *attrs;
+ struct conf_list_node *attr;
+ struct cert_handler *handler;
+ int i;
+ char *id_doi, *id_trp;
+
+#ifdef USE_DEBUG
+ exchange_dump("exchange_finalize", exchange);
+#endif
+
+ /* Copy the ID from phase 1 to exchange or phase 2 SA. */
+ if (msg->isakmp_sa) {
+ if (exchange->id_i && exchange->id_r) {
+ ipsec_clone_id(&msg->isakmp_sa->id_i,
+ &msg->isakmp_sa->id_i_len, exchange->id_i,
+ exchange->id_i_len);
+ ipsec_clone_id(&msg->isakmp_sa->id_r,
+ &msg->isakmp_sa->id_r_len, exchange->id_r,
+ exchange->id_r_len);
+ } else if (msg->isakmp_sa->id_i && msg->isakmp_sa->id_r) {
+ ipsec_clone_id(&exchange->id_i, &exchange->id_i_len,
+ msg->isakmp_sa->id_i, msg->isakmp_sa->id_i_len);
+ ipsec_clone_id(&exchange->id_r, &exchange->id_r_len,
+ msg->isakmp_sa->id_r, msg->isakmp_sa->id_r_len);
+ }
+ }
+ /*
+ * Walk over all the SAs and noting them as ready. If we set the
+ * COMMIT bit, tell the peer each SA is connected.
+ *
+ * XXX The decision should really be based on if a SA was installed
+ * successfully.
+ */
+ for (sa = TAILQ_FIRST(&exchange->sa_list); sa;
+ sa = TAILQ_NEXT(sa, next)) {
+ /* Move over the name to the SA. */
+ sa->name = exchange->name ? strdup(exchange->name) : 0;
+
+ if (exchange->flags & EXCHANGE_FLAG_I_COMMITTED) {
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link))
+ for (i = 0; i < 2; i++)
+ message_send_notification(exchange->last_received,
+ msg->isakmp_sa,
+ ISAKMP_NOTIFY_STATUS_CONNECTED,
+ proto, i);
+ }
+ /*
+ * Locate any old SAs and mark them replaced
+ * (SA_FLAG_REPLACED).
+ */
+ sa->initiator = exchange->initiator;
+ while ((old_sa = sa_find(exchange_check_old_sa, sa)) != 0)
+ sa_mark_replaced(old_sa);
+
+ /* Setup the SA flags. */
+ sa->flags |= SA_FLAG_READY;
+ if (exchange->name) {
+ attrs = conf_get_list(exchange->name, "Flags");
+ if (attrs) {
+ for (attr = TAILQ_FIRST(&attrs->fields); attr;
+ attr = TAILQ_NEXT(attr, link))
+ sa->flags |= sa_flag(attr->field);
+ conf_free_list(attrs);
+ }
+ /* 'Connections' should stay alive. */
+ if (connection_exist(exchange->name)) {
+ sa->flags |= SA_FLAG_STAYALIVE;
+
+ /*
+ * ISAKMP SA of this connection should also
+ * stay alive.
+ */
+ if (exchange->phase == 2 && msg->isakmp_sa)
+ msg->isakmp_sa->flags |=
+ SA_FLAG_STAYALIVE;
+ }
+ }
+ sa->seq = exchange->seq;
+ sa->exch_type = exchange->type;
+ }
+
+ /*
+ * If this was an phase 1 SA negotiation, save the keystate in the
+ * ISAKMP SA structure for future initialization of phase 2 exchanges'
+ * keystates. Also save the Phase 1 ID and authentication
+ * information.
+ */
+ if (exchange->phase == 1 && msg->isakmp_sa) {
+ msg->isakmp_sa->keystate = exchange->keystate;
+ exchange->keystate = 0;
+
+ msg->isakmp_sa->recv_certtype = exchange->recv_certtype;
+ msg->isakmp_sa->sent_certtype = exchange->sent_certtype;
+ msg->isakmp_sa->recv_keytype = exchange->recv_keytype;
+ msg->isakmp_sa->recv_key = exchange->recv_key;
+ msg->isakmp_sa->keynote_key = exchange->keynote_key;
+ /* Reset. */
+ exchange->recv_key = 0;
+ exchange->keynote_key = 0;
+ msg->isakmp_sa->policy_id = exchange->policy_id;
+ exchange->policy_id = -1;
+ msg->isakmp_sa->initiator = exchange->initiator;
+
+ if (exchange->recv_certtype && exchange->recv_cert) {
+ handler = cert_get(exchange->recv_certtype);
+ if (handler)
+ msg->isakmp_sa->recv_cert =
+ handler->cert_dup(exchange->recv_cert);
+ }
+ if (exchange->sent_certtype) {
+ handler = cert_get(exchange->sent_certtype);
+ if (handler)
+ msg->isakmp_sa->sent_cert =
+ handler->cert_dup(exchange->sent_cert);
+ }
+ if (exchange->doi)
+ id_doi = exchange->doi->decode_ids(
+ "initiator id %s, responder id %s",
+ exchange->id_i, exchange->id_i_len,
+ exchange->id_r, exchange->id_r_len, 0);
+ else
+ id_doi = "<no doi>";
+
+ if (msg->isakmp_sa->transport)
+ id_trp =
+ msg->isakmp_sa->transport->vtbl->decode_ids(msg->isakmp_sa->transport);
+ else
+ id_trp = "<no transport>";
+
+#if defined (USE_NAT_TRAVERSAL)
+ if (exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE)
+ msg->isakmp_sa->flags |= SA_FLAG_NAT_T_ENABLE;
+ if (exchange->flags & EXCHANGE_FLAG_NAT_T_KEEPALIVE)
+ msg->isakmp_sa->flags |= SA_FLAG_NAT_T_KEEPALIVE;
+#endif
+
+ LOG_DBG((LOG_EXCHANGE, 10,
+ "exchange_finalize: phase 1 done: %s, %s", id_doi,
+ id_trp));
+
+ log_verbose("isakmpd: phase 1 done: %s, %s", id_doi, id_trp);
+ }
+ exchange->doi->finalize_exchange(msg);
+ if (exchange->finalize)
+ exchange->finalize(exchange, exchange->finalize_arg, 0);
+ exchange->finalize = 0;
+
+ /*
+ * There is no reason to keep the SAs connected to us anymore, in fact
+ * it can hurt us if we have short lifetimes on the SAs and we try
+ * to call exchange_report, where the SA list will be walked and
+ * references to freed SAs can occur.
+ */
+ while (TAILQ_FIRST(&exchange->sa_list)) {
+ sa = TAILQ_FIRST(&exchange->sa_list);
+
+ if (exchange->id_i && exchange->id_r) {
+ ipsec_clone_id(&sa->id_i, &sa->id_i_len,
+ exchange->id_i, exchange->id_i_len);
+ ipsec_clone_id(&sa->id_r, &sa->id_r_len,
+ exchange->id_r, exchange->id_r_len);
+ }
+ TAILQ_REMOVE(&exchange->sa_list, sa, next);
+ sa_release(sa);
+ }
+
+ /* If we have nothing to retransmit we can safely remove ourselves. */
+ if (!exchange->last_sent)
+ exchange_free(exchange);
+}
+
+/* Stash a nonce into the exchange data. */
+static int
+exchange_nonce(struct exchange *exchange, int peer, size_t nonce_sz,
+ u_int8_t *buf)
+{
+ u_int8_t **nonce;
+ size_t *nonce_len;
+ int initiator = exchange->initiator ^ peer;
+ char header[32];
+
+ nonce = initiator ? &exchange->nonce_i : &exchange->nonce_r;
+ nonce_len =
+ initiator ? &exchange->nonce_i_len : &exchange->nonce_r_len;
+ *nonce_len = nonce_sz;
+ *nonce = malloc(nonce_sz);
+ if (!*nonce) {
+ log_error("exchange_nonce: malloc (%lu) failed",
+ (unsigned long)nonce_sz);
+ return -1;
+ }
+ memcpy(*nonce, buf, nonce_sz);
+ snprintf(header, sizeof header, "exchange_nonce: NONCE_%c",
+ initiator ? 'i' : 'r');
+ LOG_DBG_BUF((LOG_EXCHANGE, 80, header, *nonce, nonce_sz));
+ return 0;
+}
+
+/* Generate our NONCE. */
+int
+exchange_gen_nonce(struct message *msg, size_t nonce_sz)
+{
+ struct exchange *exchange = msg->exchange;
+ u_int8_t *buf;
+
+ buf = malloc(ISAKMP_NONCE_SZ + nonce_sz);
+ if (!buf) {
+ log_error("exchange_gen_nonce: malloc (%lu) failed",
+ ISAKMP_NONCE_SZ + (unsigned long)nonce_sz);
+ return -1;
+ }
+ getrandom(buf + ISAKMP_NONCE_DATA_OFF, nonce_sz);
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_NONCE, buf,
+ ISAKMP_NONCE_SZ + nonce_sz, 1)) {
+ free(buf);
+ return -1;
+ }
+ return exchange_nonce(exchange, 0, nonce_sz,
+ buf + ISAKMP_NONCE_DATA_OFF);
+}
+
+/* Save the peer's NONCE. */
+int
+exchange_save_nonce(struct message *msg)
+{
+ struct payload *noncep;
+ struct exchange *exchange = msg->exchange;
+
+ noncep = payload_first(msg, ISAKMP_PAYLOAD_NONCE);
+ noncep->flags |= PL_MARK;
+ return exchange_nonce(exchange, 1, GET_ISAKMP_GEN_LENGTH(noncep->p) -
+ ISAKMP_NONCE_DATA_OFF, noncep->p + ISAKMP_NONCE_DATA_OFF);
+}
+
+/* Save the peer's CERT REQuests. */
+int
+exchange_save_certreq(struct message *msg)
+{
+ struct payload *cp = payload_first(msg, ISAKMP_PAYLOAD_CERT_REQ);
+ struct exchange *exchange = msg->exchange;
+ struct certreq_aca *aca;
+
+ for (; cp; cp = TAILQ_NEXT(cp, link)) {
+ cp->flags |= PL_MARK;
+ aca = certreq_decode(GET_ISAKMP_CERTREQ_TYPE(cp->p), cp->p +
+ ISAKMP_CERTREQ_AUTHORITY_OFF, GET_ISAKMP_GEN_LENGTH(cp->p)
+ - ISAKMP_CERTREQ_AUTHORITY_OFF);
+ if (aca)
+ TAILQ_INSERT_TAIL(&exchange->aca_list, aca, link);
+ }
+
+ return 0;
+}
+
+/* Free the list of pending CERTREQs. */
+void
+exchange_free_aca_list(struct exchange *exchange)
+{
+ struct certreq_aca *aca;
+
+ for (aca = TAILQ_FIRST(&exchange->aca_list); aca;
+ aca = TAILQ_FIRST(&exchange->aca_list)) {
+ if (aca->data) {
+ if (aca->handler)
+ aca->handler->free_aca(aca->data);
+ free(aca->data);
+ }
+ TAILQ_REMOVE(&exchange->aca_list, aca, link);
+ free(aca);
+ }
+}
+
+/* Obtain certificates from acceptable certification authority. */
+int
+exchange_add_certs(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct certreq_aca *aca;
+ u_int8_t *cert = 0, *new_cert = 0;
+ u_int32_t certlen;
+ u_int8_t *id;
+ size_t id_len;
+
+ id = exchange->initiator ? exchange->id_r : exchange->id_i;
+ id_len = exchange->initiator ? exchange->id_r_len : exchange->id_i_len;
+
+ /*
+ * Without IDs we cannot handle this yet. Keep the aca_list around for
+ * a later step/retry to see if we got the ID by then.
+ * Note: A 'return -1' breaks X509-auth interop in the responder case
+ * with some IPsec clients that send CERTREQs early (such as
+ * the SSH Sentinel).
+ */
+ if (!id)
+ return 0;
+
+ for (aca = TAILQ_FIRST(&exchange->aca_list); aca;
+ aca = TAILQ_NEXT(aca, link)) {
+ /* XXX? If we can not satisfy a CERTREQ we drop the message. */
+ if (!aca->handler->cert_obtain(id, id_len, aca->data, &cert,
+ &certlen)) {
+ log_print("exchange_add_certs: could not obtain cert "
+ "for a type %d cert request", aca->id);
+ if (cert)
+ free(cert);
+ return -1;
+ }
+ new_cert = realloc(cert, ISAKMP_CERT_SZ + certlen);
+ if (!new_cert) {
+ log_error("exchange_add_certs: realloc (%p, %d) "
+ "failed", cert, ISAKMP_CERT_SZ + certlen);
+ if (cert)
+ free(cert);
+ return -1;
+ }
+ cert = new_cert;
+ memmove(cert + ISAKMP_CERT_DATA_OFF, cert, certlen);
+ SET_ISAKMP_CERT_ENCODING(cert, aca->id);
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_CERT, cert,
+ ISAKMP_CERT_SZ + certlen, 1)) {
+ free(cert);
+ return -1;
+ }
+ }
+
+ /* We dont need the CERT REQs any more, they are answered. */
+ exchange_free_aca_list(exchange);
+
+ return 0;
+}
+
+static void
+exchange_establish_finalize(struct exchange *exchange, void *arg, int fail)
+{
+ char *name = arg;
+
+ LOG_DBG((LOG_EXCHANGE, 20, "exchange_establish_finalize: "
+ "finalizing exchange %p with arg %p (%s) & fail = %d",
+ exchange, arg, name ? name : "<unnamed>", fail));
+
+ if (!fail)
+ exchange_establish(name, 0, 0);
+ free(name);
+}
+
+/*
+ * Establish an exchange named NAME, and record the FINALIZE function
+ * taking ARG as an argument to be run after the exchange is ready.
+ */
+void
+exchange_establish(char *name, void (*finalize)(struct exchange *, void *,
+ int), void *arg)
+{
+ struct transport *transport;
+ struct sa *isakmp_sa;
+ struct exchange *exchange;
+ int phase;
+ char *trpt, *peer;
+
+ phase = conf_get_num(name, "Phase", 0);
+
+ /*
+ * First of all, never try to establish anything if another exchange
+ * of the same kind is running.
+ */
+ exchange = exchange_lookup_by_name(name, phase);
+ if (exchange) {
+ LOG_DBG((LOG_EXCHANGE, 40,
+ "exchange_establish: %s exchange already exists as %p",
+ name, exchange));
+ exchange_add_finalization(exchange, finalize, arg);
+ return;
+ }
+ switch (phase) {
+ case 1:
+ trpt = conf_get_str(name, "Transport");
+ if (!trpt) {
+ /* Phase 1 transport defaults to "udp". */
+ trpt = ISAKMP_DEFAULT_TRANSPORT;
+ }
+ transport = transport_create(trpt, name);
+ if (!transport) {
+ log_print("exchange_establish: transport \"%s\" for "
+ "peer \"%s\" could not be created", trpt, name);
+ return;
+ }
+ exchange_establish_p1(transport, 0, 0, name, 0, finalize, arg);
+ break;
+
+ case 2:
+ peer = conf_get_str(name, "ISAKMP-peer");
+ if (!peer) {
+ log_print("exchange_establish: No ISAKMP-peer given "
+ "for \"%s\"", name);
+ return;
+ }
+ isakmp_sa = sa_lookup_by_name(peer, 1);
+ if (!isakmp_sa) {
+ name = strdup(name);
+ if (!name) {
+ log_error("exchange_establish: "
+ "strdup (\"%s\") failed", name);
+ return;
+ }
+ if (conf_get_num(peer, "Phase", 0) != 1) {
+ log_print("exchange_establish: "
+ "[%s]:ISAKMP-peer's (%s) phase is not 1",
+ name, peer);
+ return;
+ }
+ /*
+ * XXX We're losing information here (what the
+ * original finalize routine was. As a result, if an
+ * exchange does not manage to get through, there may
+ * be application-specific information that won't get
+ * cleaned up, since no error signalling will be done.
+ * This is the case with dynamic SAs and PFKEY.
+ */
+ exchange_establish(peer, exchange_establish_finalize,
+ name);
+ exchange = exchange_lookup_by_name(peer, 1);
+ /*
+ * If the exchange was correctly initialized, add the
+ * original finalization routine; otherwise, call it
+ * directly.
+ */
+ if (exchange)
+ exchange_add_finalization(exchange, finalize,
+ arg);
+ else
+ finalize(0, arg, 1); /* Indicate failure */
+ return;
+ } else
+ exchange_establish_p2(isakmp_sa, 0, name, 0, finalize,
+ arg);
+ break;
+
+ default:
+ log_print("exchange_establish: "
+ "peer \"%s\" does not have a correct phase (%d)",
+ name, phase);
+ break;
+ }
+}
diff --git a/keyexchange/isakmpd-20041012/exchange.h b/keyexchange/isakmpd-20041012/exchange.h
new file mode 100644
index 0000000..67061c0
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/exchange.h
@@ -0,0 +1,252 @@
+/* $OpenBSD: exchange.h,v 1.28 2004/08/23 11:13:14 ho Exp $ */
+/* $EOM: exchange.h,v 1.28 2000/09/28 12:54:28 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _EXCHANGE_H_
+#define _EXCHANGE_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "exchange_num.h"
+#include "isakmp.h"
+
+/* Remove an exchange if it has not been fully negotiated in this time. */
+#define EXCHANGE_MAX_TIME 120
+
+struct crypto_xf;
+struct certreq_aca;
+struct doi;
+struct event;
+struct keystate;
+struct message;
+struct payload;
+struct transport;
+struct sa;
+
+struct exchange {
+ /* Link to exchanges with the same hash value. */
+ LIST_ENTRY(exchange) link;
+
+ /* A name of the SAs this exchange will result in. XXX non unique? */
+ char *name;
+
+ /*
+ * A name of the major policy deciding offers and acceptable
+ * proposals.
+ */
+ char *policy;
+
+ /*
+ * A function with a polymorphic argument called after the exchange
+ * has been run to its end, successfully. The 2nd argument is true
+ * if the finalization hook is called due to the exchange not running
+ * to its end normally.
+ */
+ void (*finalize)(struct exchange *, void *, int);
+ void *finalize_arg;
+
+ /* When several SA's are being negotiated we keep them here. */
+ TAILQ_HEAD(sa_head, sa) sa_list;
+
+ /*
+ * The event that will occur when it has taken too long time to try to
+ * run the exchange and which will trigger auto-destruction.
+ */
+ struct event *death;
+
+ /*
+ * Both initiator and responder cookies.
+ * XXX For code clarity we might split this into two fields.
+ */
+ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN];
+
+ /* The message ID signifying phase 2 exchanges. */
+ u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN];
+
+ /* The exchange type we are using. */
+ u_int8_t type;
+
+ /* Phase is 1 for ISAKMP SA exchanges, and 2 for application ones. */
+ u_int8_t phase;
+
+ /* The "step counter" of the exchange, starting from zero. */
+ u_int8_t step;
+
+ /* 1 if we are the initiator, 0 if we are the responder. */
+ u_int8_t initiator;
+
+ /* Various flags, look below for descriptions. */
+ u_int32_t flags;
+
+ /* The DOI that is to handle DOI-specific issues for this exchange. */
+ struct doi *doi;
+
+ /*
+ * A "program counter" into the script that validate message contents
+ * for this exchange.
+ */
+ int16_t *exch_pc;
+
+ /* The last message received, used for checking for duplicates. */
+ struct message *last_received;
+
+ /* The last message sent, to be acked when something new is received. */
+ struct message *last_sent;
+
+ /*
+ * If some message is queued up for sending, we want to be able to
+ * remove it from the queue, when the exchange is deleted.
+ */
+ struct message *in_transit;
+
+ /*
+ * Initiator's & responder's nonces respectively, with lengths.
+ * XXX Should this be in the DOI-specific parts instead?
+ */
+ u_int8_t *nonce_i;
+ size_t nonce_i_len;
+ u_int8_t *nonce_r;
+ size_t nonce_r_len;
+
+ /*
+ * The ID payload contents for the initiator & responder,
+ * respectively.
+ */
+ u_int8_t *id_i;
+ size_t id_i_len;
+ u_int8_t *id_r;
+ size_t id_r_len;
+
+ /* Policy session identifier, where applicable. */
+ int policy_id;
+
+ /* Crypto info needed to encrypt/decrypt packets in this exchange. */
+ struct crypto_xf *crypto;
+ size_t key_length;
+ struct keystate *keystate;
+
+ /*
+ * Used only by KeyNote, to cache the key used to authenticate Phase
+ * 1
+ */
+ char *keynote_key; /* printable format */
+
+ /*
+ * Received certificate - used to verify signatures on packet,
+ * stored here for later policy processing.
+ *
+ * The rules for the recv_* and sent_* fields are:
+ * - recv_cert stores the credential (if any) received from the peer;
+ * the kernel may pass us one, but we ignore it. We pass it to the
+ * kernel so processes can peek at it. When doing passphrase
+ * authentication in Phase 1, this is empty.
+ * - recv_key stores the key (public or private) used by the peer
+ * to authenticate. Otherwise, same properties as recv_cert except
+ * that we don't tell the kernel about passphrases (so we don't
+ * reveal system-wide passphrases). Processes that used passphrase
+ * authentication already know the passphrase! We ignore it if/when
+ * received from the kernel (meaningless).
+ * - sent_cert stores the credential, if any, we used to authenticate
+ * with the peer. It may be passed to us by the kernel, or we may
+ * have found it in our certificate storage. In either case, there's
+ * no point passing it to the kernel, so we don't.
+ * - sent key stores the private key we used for authentication with
+ * the peer (private key or passphrase). This may have been received
+ * from the kernel, or may be a system-wide setting. In either case,
+ * we don't pass it to the kernel, to avoid revealing such information
+ * to processes (processes either already know it, or have no business
+ * knowing it).
+ */
+ int recv_certtype, recv_keytype;
+ void *recv_cert; /* Certificate received from peer,
+ * native format */
+ void *recv_key; /* Key peer used to authenticate,
+ * native format */
+
+ /* Likewise, for certificates/keys we use. */
+ int sent_certtype, sent_keytype;
+ void *sent_cert; /* Certificate (to be) sent to peer,
+ * native format */
+ void *sent_key; /* Key we'll use to authenticate to
+ * peer, native format */
+
+ /* ACQUIRE sequence number. */
+ u_int32_t seq;
+
+ /* XXX This is no longer necessary, it is covered by policy. */
+
+ /* Acceptable authorities for cert requests. */
+ TAILQ_HEAD(aca_head, certreq_aca) aca_list;
+
+ /* DOI-specific opaque data. */
+ void *data;
+};
+
+/* The flag bits. */
+#define EXCHANGE_FLAG_I_COMMITTED 0x01
+#define EXCHANGE_FLAG_HE_COMMITTED 0x02
+#define EXCHANGE_FLAG_COMMITTED (EXCHANGE_FLAG_I_COMMITTED \
+ | EXCHANGE_FLAG_HE_COMMITTED)
+#define EXCHANGE_FLAG_ENCRYPT 0x04
+#define EXCHANGE_FLAG_NAT_T_CAP_PEER 0x08 /* Peer is NAT capable. */
+#define EXCHANGE_FLAG_NAT_T_ENABLE 0x10 /* We are doing NAT-T. */
+#define EXCHANGE_FLAG_NAT_T_KEEPALIVE 0x20 /* We are the NAT:ed peer. */
+#define EXCHANGE_FLAG_DPD_CAP_PEER 0x40 /* Peer is DPD capable. */
+#define EXCHANGE_FLAG_NAT_T_RFC 0x0080 /* Peer does RFC NAT-T. */
+#define EXCHANGE_FLAG_NAT_T_DRAFT 0x0100 /* Peer does draft NAT-T.*/
+
+extern int exchange_add_certs(struct message *);
+extern void exchange_finalize(struct message *);
+extern void exchange_free(struct exchange *);
+extern void exchange_free_aca_list(struct exchange *);
+extern void exchange_establish(char *name, void (*)(struct exchange *,
+ void *, int), void *);
+extern void exchange_establish_p1(struct transport *, u_int8_t, u_int32_t,
+ char *, void *, void (*)(struct exchange *, void *, int),
+ void *);
+extern void exchange_establish_p2(struct sa *, u_int8_t, char *, void *,
+ void (*)(struct exchange *, void *, int), void *);
+extern int exchange_gen_nonce(struct message *, size_t);
+extern void exchange_init(void);
+extern struct exchange *exchange_lookup(u_int8_t *, int);
+extern struct exchange *exchange_lookup_by_name(char *, int);
+extern struct exchange *exchange_lookup_from_icookie(u_int8_t *);
+extern void exchange_report(void);
+extern void exchange_run(struct message *);
+extern int exchange_save_nonce(struct message *);
+extern int exchange_save_certreq(struct message *);
+extern int16_t *exchange_script(struct exchange *);
+extern struct exchange *exchange_setup_p1(struct message *, u_int32_t);
+extern struct exchange *exchange_setup_p2(struct message *, u_int8_t);
+extern void exchange_upgrade_p1(struct message *);
+
+#endif /* _EXCHANGE_H_ */
diff --git a/keyexchange/isakmpd-20041012/exchange_num.cst b/keyexchange/isakmpd-20041012/exchange_num.cst
new file mode 100644
index 0000000..7f61568
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/exchange_num.cst
@@ -0,0 +1,42 @@
+# $OpenBSD: exchange_num.cst,v 1.4 2003/06/03 14:28:16 ho Exp $
+# $EOM: exchange_num.cst,v 1.1 1998/08/05 09:23:32 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# Special exchange script symbols.
+EXCHANGE_SCRIPT
+# Special type signifying PAYLOAD_HASH or PALOAD_SIG must be present.
+ AUTH -1
+# Special type signifying PAYLOAD_NOTIFY or PALOAD_DELETE must be present.
+ INFO -2
+# Switch roles at this point in the exchange.
+ SWITCH -3
+# End of script
+ END -4
+.
diff --git a/keyexchange/isakmpd-20041012/features/aggressive b/keyexchange/isakmpd-20041012/features/aggressive
new file mode 100644
index 0000000..945678c
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/aggressive
@@ -0,0 +1,32 @@
+# $OpenBSD: aggressive,v 1.4 2003/06/03 14:29:41 ho Exp $
+# $EOM: aggressive,v 1.3 2000/02/20 16:38:15 niklas Exp $
+
+#
+# Copyright (c) 2000 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Wireless Networks Inc.
+#
+
+AGGRESSIVE= ike_aggressive.c
diff --git a/keyexchange/isakmpd-20041012/features/dnssec b/keyexchange/isakmpd-20041012/features/dnssec
new file mode 100644
index 0000000..aab768d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/dnssec
@@ -0,0 +1,30 @@
+# $OpenBSD: dnssec,v 1.3 2003/06/03 14:29:41 ho Exp $
+
+#
+# Copyright (c) 2001 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+DNSSEC= dnssec.c
+
+#LWRESLIB= /usr/local/lib/liblwres.a
+#DNSSEC_CFLAGS= -I/usr/local/include -DLWRES
diff --git a/keyexchange/isakmpd-20041012/features/dpd b/keyexchange/isakmpd-20041012/features/dpd
new file mode 100644
index 0000000..155ce68
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/dpd
@@ -0,0 +1,27 @@
+# $OpenBSD: dpd,v 1.1 2004/06/20 15:20:07 ho Exp $
+
+#
+# Copyright (c) 2004 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+DPD= dpd.c
diff --git a/keyexchange/isakmpd-20041012/features/ec b/keyexchange/isakmpd-20041012/features/ec
new file mode 100644
index 0000000..6452a8e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/ec
@@ -0,0 +1,32 @@
+# $OpenBSD: ec,v 1.4 2003/06/03 14:29:41 ho Exp $
+# $EOM: ec,v 1.3 2000/02/20 16:38:15 niklas Exp $
+
+#
+# Copyright (c) 2000 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Wireless Networks Inc.
+#
+
+EC= math_ec2n.c
diff --git a/keyexchange/isakmpd-20041012/features/isakmp_cfg b/keyexchange/isakmpd-20041012/features/isakmp_cfg
new file mode 100644
index 0000000..55710fc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/isakmp_cfg
@@ -0,0 +1,31 @@
+# $OpenBSD: isakmp_cfg,v 1.2 2003/06/03 14:29:41 ho Exp $
+
+#
+# Copyright (c) 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Gatespace (http://www.gatespace.com/).
+#
+
+ISAKMP_CFG= isakmp_cfg.c
diff --git a/keyexchange/isakmpd-20041012/features/nat_traversal b/keyexchange/isakmpd-20041012/features/nat_traversal
new file mode 100644
index 0000000..590b4bf
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/nat_traversal
@@ -0,0 +1,27 @@
+# $OpenBSD: nat_traversal,v 1.2 2004/06/21 17:02:53 markus Exp $
+
+#
+# Copyright (c) 2004 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+NAT_TRAVERSAL= nat_traversal.c udp_encap.c
diff --git a/keyexchange/isakmpd-20041012/features/policy b/keyexchange/isakmpd-20041012/features/policy
new file mode 100644
index 0000000..680cc37
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/policy
@@ -0,0 +1,33 @@
+# $OpenBSD: policy,v 1.6 2003/06/03 14:29:41 ho Exp $
+# $EOM: policy,v 1.4 2000/02/20 16:38:15 niklas Exp $
+
+#
+# Copyright (c) 2000 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Wireless Networks Inc.
+#
+
+# NOTE: KeyNote policy support requires the keynote library
+POLICY= policy.c
diff --git a/keyexchange/isakmpd-20041012/features/privsep b/keyexchange/isakmpd-20041012/features/privsep
new file mode 100644
index 0000000..20690a0
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/privsep
@@ -0,0 +1,27 @@
+# $OpenBSD: privsep,v 1.2 2003/06/03 14:29:41 ho Exp $
+
+#
+# Copyright (c) 2003 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+PRIVSEP= monitor.c monitor_fdpass.c
diff --git a/keyexchange/isakmpd-20041012/features/x509 b/keyexchange/isakmpd-20041012/features/x509
new file mode 100644
index 0000000..be1b2aa
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/features/x509
@@ -0,0 +1,32 @@
+# $OpenBSD: x509,v 1.5 2003/06/03 14:29:41 ho Exp $
+# $EOM: x509,v 1.4 2000/02/20 16:38:15 niklas Exp $
+
+#
+# Copyright (c) 2000 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Wireless Networks Inc.
+#
+
+X509= x509.c
diff --git a/keyexchange/isakmpd-20041012/field.c b/keyexchange/isakmpd-20041012/field.c
new file mode 100644
index 0000000..0cc96d2
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/field.c
@@ -0,0 +1,252 @@
+/* $OpenBSD: field.c,v 1.16 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: field.c,v 1.11 2000/02/20 19:58:37 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "constants.h"
+#include "field.h"
+#include "log.h"
+#include "util.h"
+
+static char *field_debug_raw(u_int8_t *, size_t, struct constant_map **);
+static char *field_debug_num(u_int8_t *, size_t, struct constant_map **);
+static char *field_debug_mask(u_int8_t *, size_t, struct constant_map **);
+static char *field_debug_ign(u_int8_t *, size_t, struct constant_map **);
+static char *field_debug_cst(u_int8_t *, size_t, struct constant_map **);
+
+/* Contents must match the enum in struct field. */
+static char *(*decode_field[]) (u_int8_t *, size_t,
+ struct constant_map **) = {
+ field_debug_raw,
+ field_debug_num,
+ field_debug_mask,
+ field_debug_ign,
+ field_debug_cst
+};
+
+/*
+ * Return a string showing the hexadecimal contents of the LEN-sized buffer
+ * BUF. MAPS should be zero and is only here because the API requires it.
+ */
+static char *
+field_debug_raw(u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ char *retval, *p;
+
+ if (len == 0)
+ return 0;
+ retval = malloc(3 + len * 2);
+ if (!retval)
+ return 0;
+ strlcpy(retval, "0x", 3 + len * 2);
+ p = retval + 2;
+ for (; len > 0; len--) {
+ snprintf(p, 1 + len * 2, "%02x", *buf++);
+ p += 2;
+ }
+ return retval;
+}
+
+/*
+ * Convert the unsigned LEN-sized number at BUF of network byteorder to a
+ * 32-bit unsigned integer of host byteorder pointed to by VAL.
+ */
+static int
+extract_val(u_int8_t *buf, size_t len, u_int32_t *val)
+{
+ switch (len) {
+ case 1:
+ *val = *buf;
+ break;
+ case 2:
+ *val = decode_16(buf);
+ break;
+ case 4:
+ *val = decode_32(buf);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Return a textual representation of the unsigned number pointed to by BUF
+ * which is LEN octets long. MAPS should be zero and is only here because
+ * the API requires it.
+ */
+static char *
+field_debug_num(u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ char *retval;
+ u_int32_t val;
+
+ if (extract_val(buf, len, &val))
+ return 0;
+ /* 3 decimal digits are enough to represent each byte. */
+ retval = malloc(3 * len);
+ snprintf(retval, 3 * len, "%u", val);
+ return retval;
+}
+
+/*
+ * Return the symbolic names of the flags pointed to by BUF which is LEN
+ * octets long, using the constant maps MAPS.
+ */
+static char *
+field_debug_mask(u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ u_int32_t val;
+ u_int32_t bit;
+ char *retval, *new_buf, *name;
+ size_t buf_sz;
+
+ if (extract_val(buf, len, &val))
+ return 0;
+
+ /* Size for brackets, two spaces and a NUL terminator. */
+ buf_sz = 4;
+ retval = malloc(buf_sz);
+ if (!retval)
+ return 0;
+
+ strlcpy(retval, "[ ", buf_sz);
+ for (bit = 1; bit; bit <<= 1) {
+ if (val & bit) {
+ name = constant_name_maps(maps, bit);
+ buf_sz += strlen(name) + 1;
+ new_buf = realloc(retval, buf_sz);
+ if (!new_buf) {
+ free(retval);
+ return 0;
+ }
+ retval = new_buf;
+ strlcat(retval, name, buf_sz);
+ strlcat(retval, " ", buf_sz);
+ }
+ }
+ strlcat(retval, "]", buf_sz);
+ return retval;
+}
+
+/*
+ * Just a dummy needed to skip the unused LEN sized space at BUF. MAPS
+ * should be zero and is only here because the API requires it.
+ */
+static char *
+field_debug_ign(u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ return 0;
+}
+
+/*
+ * Return the symbolic name of a constant pointed to by BUF which is LEN
+ * octets long, using the constant maps MAPS.
+ */
+static char *
+field_debug_cst(u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ u_int32_t val;
+
+ if (extract_val(buf, len, &val))
+ return 0;
+
+ return strdup(constant_name_maps(maps, val));
+}
+
+/* Pretty-print a field from BUF as described by F. */
+void
+field_dump_field(struct field *f, u_int8_t *buf)
+{
+ char *value;
+
+ value = decode_field[(int) f->type] (buf + f->offset, f->len, f->maps);
+ if (value) {
+ LOG_DBG((LOG_MESSAGE, 70, "%s: %s", f->name, value));
+ free(value);
+ }
+}
+
+/* Pretty-print all the fields of BUF as described in FIELDS. */
+void
+field_dump_payload(struct field *fields, u_int8_t *buf)
+{
+ struct field *field;
+
+ for (field = fields; field->name; field++)
+ field_dump_field(field, buf);
+}
+
+/* Return the numeric value of the field F of BUF. */
+u_int32_t
+field_get_num(struct field *f, u_int8_t *buf)
+{
+ u_int32_t val;
+
+ if (extract_val(buf + f->offset, f->len, &val))
+ return 0;
+ return val;
+}
+
+/* Stash the number VAL into BUF's field F. */
+void
+field_set_num(struct field *f, u_int8_t *buf, u_int32_t val)
+{
+ switch (f->len) {
+ case 1:
+ buf[f->offset] = val;
+ break;
+ case 2:
+ encode_16(buf + f->offset, val);
+ break;
+ case 4:
+ encode_32(buf + f->offset, val);
+ break;
+ }
+}
+
+/* Stash BUF's raw field F into VAL. */
+void
+field_get_raw(struct field *f, u_int8_t *buf, u_int8_t *val)
+{
+ memcpy(val, buf + f->offset, f->len);
+}
+
+/* Stash the buffer VAL into BUF's field F. */
+void
+field_set_raw(struct field *f, u_int8_t *buf, u_int8_t *val)
+{
+ memcpy(buf + f->offset, val, f->len);
+}
diff --git a/keyexchange/isakmpd-20041012/field.h b/keyexchange/isakmpd-20041012/field.h
new file mode 100644
index 0000000..428d417
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/field.h
@@ -0,0 +1,54 @@
+/* $OpenBSD: field.h,v 1.6 2004/05/23 18:17:55 hshoexer Exp $ */
+/* $EOM: field.h,v 1.3 1998/08/02 20:25:01 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _FIELD_H_
+#define _FIELD_H_
+
+#include <sys/types.h>
+
+struct field {
+ char *name;
+ int offset;
+ size_t len;
+ enum {
+ raw, num, mask, ign, cst
+ } type;
+ struct constant_map **maps;
+};
+
+extern void field_dump_field(struct field *, u_int8_t *);
+extern void field_dump_payload(struct field *, u_int8_t *);
+extern u_int32_t field_get_num(struct field *, u_int8_t *);
+extern void field_get_raw(struct field *, u_int8_t *, u_int8_t *);
+extern void field_set_num(struct field *, u_int8_t *, u_int32_t);
+extern void field_set_raw(struct field *, u_int8_t *, u_int8_t *);
+
+#endif /* _FIELD_H_ */
diff --git a/keyexchange/isakmpd-20041012/genconstants.sh b/keyexchange/isakmpd-20041012/genconstants.sh
new file mode 100644
index 0000000..8332209
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/genconstants.sh
@@ -0,0 +1,114 @@
+# $OpenBSD: genconstants.sh,v 1.12 2004/04/15 18:39:25 deraadt Exp $
+# $EOM: genconstants.sh,v 1.6 1999/04/02 01:15:53 niklas Exp $
+
+#
+# Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+base=`basename $1`
+upcased_name=`echo $base |tr a-z A-Z`
+
+awk=${AWK:-awk}
+
+locase_function='function locase (str) {
+ cmd = "echo " str " |tr A-Z a-z"
+ cmd | getline retval;
+ close (cmd);
+ return retval;
+}'
+
+$awk "
+$locase_function
+"'
+BEGIN {
+ print "/* DO NOT EDIT-- this file is automatically generated. */\n"
+ print "#ifndef _'$upcased_name'_H_"
+ print "#define _'$upcased_name'_H_\n"
+ print "#include \"sysdep.h\"\n"
+ print "#include \"constants.h\"\n"
+}
+
+/^[#.]/ {
+ next
+}
+
+/^[^ ]/ {
+ prefix = $1
+ printf ("extern struct constant_map %s_cst[];\n\n", locase(prefix));
+ next
+}
+
+/^[ ]/ && $1 {
+ printf ("#define %s_%s %s\n", prefix, $1, $2)
+ next
+}
+
+{
+ print
+}
+
+END {
+ printf ("\n")
+ print "#endif /* _'$upcased_name'_H_ */"
+}
+' <$1.cst >$base.h
+
+$awk "
+$locase_function
+"'
+BEGIN {
+ print "/* DO NOT EDIT-- this file is automatically generated. */\n"
+ print "#include \"sysdep.h\"\n"
+ print "#include \"constants.h\""
+ print "#include \"'$base'.h\"\n"
+}
+
+/^#/ {
+ next
+}
+
+/^\./ {
+ print " { 0, 0 }\n};\n"
+ next
+}
+
+/^[^ ]/ {
+ prefix = $1
+ printf ("struct constant_map %s_cst[] = {\n", locase(prefix))
+ next
+}
+
+/^[ ]/ && $1 {
+ printf (" { %s_%s, \"%s\", %s },\n", prefix, $1, $1,
+ ($3 && substr($3,1,1) != "#") ? $3 : 0)
+ next
+}
+
+{
+ print
+}
+' <$1.cst >$base.c
diff --git a/keyexchange/isakmpd-20041012/genfields.sh b/keyexchange/isakmpd-20041012/genfields.sh
new file mode 100644
index 0000000..74909e1
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/genfields.sh
@@ -0,0 +1,185 @@
+# $OpenBSD: genfields.sh,v 1.9 2004/04/15 18:39:25 deraadt Exp $
+# $EOM: genfields.sh,v 1.5 1999/04/02 01:15:55 niklas Exp $
+
+#
+# Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+base=`basename $1`
+upcased_name=`echo $base |tr a-z A-Z`
+
+awk=${AWK:-awk}
+
+locase_function='function locase (str) {
+ cmd = "echo " str " |tr A-Z a-z"
+ cmd | getline retval;
+ close (cmd);
+ return retval;
+}'
+
+$awk "
+$locase_function
+"'
+BEGIN {
+ print "/* DO NOT EDIT-- this file is automatically generated. */\n"
+ print "#ifndef _'$upcased_name'_H_"
+ print "#define _'$upcased_name'_H_\n"
+
+ print "#include \"sysdep.h\"\n"
+ print "#include \"field.h\"\n"
+
+ print "struct constant_map;\n"
+}
+
+/^#/ {
+ next
+}
+
+/^\./ {
+ printf ("#define %s_SZ %d\n", prefix, off)
+ size[prefix] = off
+ next
+}
+
+/^[^ ]/ {
+ prefix = $1
+ printf ("extern struct field %s_fld[];\n\n", locase(prefix));
+ if ($3)
+ {
+ off = size[$3]
+ }
+ else
+ {
+ off = 0
+ }
+ i = 0
+ next
+}
+
+/^[ ]/ && $1 {
+ printf ("#define %s_%s_OFF %d\n", prefix, $1, off)
+ if ($3)
+ {
+ printf ("#define %s_%s_LEN %d\n", prefix, $1, $3)
+ }
+ if ($4)
+ {
+ printf ("extern struct constant_map *%s_%s_maps[];\n", locase(prefix),
+ locase($1))
+ }
+ if ($2 == "raw")
+ {
+ printf ("#define GET_%s_%s(buf, val) ", prefix, $1)
+ printf ("field_get_raw (%s_fld + %d, buf, val)\n", locase(prefix), i)
+ printf ("#define SET_%s_%s(buf, val) ", prefix, $1)
+ printf ("field_set_raw (%s_fld + %d, buf, val)\n", locase(prefix), i)
+ }
+ else
+ {
+ printf ("#define GET_%s_%s(buf) field_get_num (%s_fld + %d, buf)\n",
+ prefix, $1, locase(prefix), i)
+ printf ("#define SET_%s_%s(buf, val) ", prefix, $1)
+ printf ("field_set_num (%s_fld + %d, buf, val)\n", locase(prefix), i)
+ }
+ off += $3
+ i++
+ next
+}
+
+{
+ print
+}
+
+END {
+ printf ("\n")
+ print "#endif /* _'$upcased_name'_H_ */"
+}
+' <$1.fld >$base.h
+
+$awk "
+$locase_function
+"'
+BEGIN {
+ print "/* DO NOT EDIT-- this file is automatically generated. */\n"
+ print "#include \"sysdep.h\"\n"
+ print "#include \"constants.h\""
+ print "#include \"field.h\""
+ print "#include \"'$base'.h\""
+ print "#include \"isakmp_num.h\""
+ print "#include \"ipsec_num.h\"\n"
+}
+
+/^#/ {
+ next
+}
+
+/^\./ {
+ print " { 0, 0, 0, 0, 0 }\n};\n"
+ size[prefix] = off
+ for (map in maps)
+ {
+ printf ("struct constant_map *%s_%s_maps[] = {\n", locase(prefix),
+ locase(map))
+ printf (" %s, 0\n};\n", maps[map])
+ }
+ next
+}
+
+/^[^ ]/ {
+ prefix = $1
+ printf ("struct field %s_fld[] = {\n", locase(prefix))
+ if ($3)
+ {
+ off = size[$3]
+ }
+ else
+ {
+ off = 0
+ }
+ delete maps
+ next
+}
+
+/^[ ]/ && $1 {
+ if ($4)
+ {
+ maps_name = locase(prefix)"_"locase($1)"_maps"
+ maps[$1] = $4
+ }
+ else
+ {
+ maps_name = "0"
+ }
+ printf (" { \"%s\", %d, %d, %s, %s },\n", $1, off, $3, $2, maps_name)
+ off += $3
+ next
+}
+
+{
+ print
+}
+' <$1.fld >$base.c
diff --git a/keyexchange/isakmpd-20041012/gmp_util.c b/keyexchange/isakmpd-20041012/gmp_util.c
new file mode 100644
index 0000000..2a338d2
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/gmp_util.c
@@ -0,0 +1,105 @@
+/* $OpenBSD: gmp_util.c,v 1.11 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: gmp_util.c,v 1.7 2000/09/18 00:01:47 ho Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+
+#include "sysdep.h"
+
+#include "gmp_util.h"
+#include "math_mp.h"
+
+/* Various utility functions for gmp, used in more than one module */
+
+u_int32_t
+mpz_sizeinoctets(math_mp_t a)
+{
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ return (7 + mpz_sizeinbase(a, 2)) >> 3;
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ return BN_num_bytes(a);
+#endif
+}
+
+void
+mpz_getraw(u_int8_t *raw, math_mp_t v, u_int32_t len)
+{
+ math_mp_t a;
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ math_mp_t tmp;
+
+ /* XXX mpz_get_str (raw, BASE, v); ? */
+ mpz_init_set(a, v);
+ mpz_init(tmp);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ /* XXX bn2bin? */
+ a = BN_dup(v);
+#endif
+
+ while (len-- > 0)
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ raw[len] = mpz_fdiv_qr_ui(a, tmp, a, 256);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ raw[len] = BN_div_word(a, 256);
+#endif
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ mpz_clear(a);
+ mpz_clear(tmp);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ BN_clear_free(a);
+#endif
+}
+
+void
+mpz_setraw(math_mp_t d, u_int8_t *s, u_int32_t l)
+{
+ u_int32_t i;
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ /* XXX mpz_set_str (d, s, 0); */
+ mpz_set_si(d, 0);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ /* XXX bin2bn? */
+ BN_set_word(d, 0);
+#endif
+ for (i = 0; i < l; i++) {
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ mpz_mul_ui(d, d, 256);
+ mpz_add_ui(d, d, s[i]);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ BN_mul_word(d, 256);
+ BN_add_word(d, s[i]);
+#endif
+ }
+}
diff --git a/keyexchange/isakmpd-20041012/gmp_util.h b/keyexchange/isakmpd-20041012/gmp_util.h
new file mode 100644
index 0000000..826c6ca
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/gmp_util.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: gmp_util.h,v 1.8 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: gmp_util.h,v 1.4 2000/05/08 13:42:11 ho Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 2000 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _GMP_UTIL_H_
+#define _GMP_UTIL_H_
+
+#include "math_mp.h"
+
+u_int32_t mpz_sizeinoctets(math_mp_t);
+void mpz_getraw(u_int8_t *, math_mp_t, u_int32_t);
+void mpz_setraw(math_mp_t, u_int8_t *, u_int32_t);
+
+#endif /* _GMP_UTIL_H_ */
diff --git a/keyexchange/isakmpd-20041012/hash.c b/keyexchange/isakmpd-20041012/hash.c
new file mode 100644
index 0000000..84773f8
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/hash.c
@@ -0,0 +1,145 @@
+/* $OpenBSD: hash.c,v 1.17 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: hash.c,v 1.10 1999/04/17 23:20:34 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <string.h>
+#if defined (__APPLE__)
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#else
+#include <md5.h>
+#include <sha1.h>
+#endif /* __APPLE__ */
+
+#include "sysdep.h"
+
+#include "hash.h"
+#include "log.h"
+
+void hmac_init(struct hash *, unsigned char *, unsigned int);
+void hmac_final(unsigned char *, struct hash *);
+
+/* Temporary hash contexts. */
+static union {
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+} Ctx, Ctx2;
+
+/* Temporary hash digest. */
+static unsigned char digest[HASH_MAX];
+
+/* Encapsulation of hash functions. */
+
+static struct hash hashes[] = {
+ {
+ HASH_MD5, 5, MD5_SIZE, (void *)&Ctx.md5ctx, digest,
+ sizeof(MD5_CTX), (void *)&Ctx2.md5ctx,
+ (void (*)(void *))MD5Init,
+ (void (*)(void *, unsigned char *, unsigned int))MD5Update,
+ (void (*)(unsigned char *, void *))MD5Final,
+ hmac_init,
+ hmac_final
+ }, {
+ HASH_SHA1, 6, SHA1_SIZE, (void *)&Ctx.sha1ctx, digest,
+ sizeof(SHA1_CTX), (void *)&Ctx2.sha1ctx,
+ (void (*)(void *))SHA1Init,
+ (void (*)(void *, unsigned char *, unsigned int))SHA1Update,
+ (void (*)(unsigned char *, void *))SHA1Final,
+ hmac_init,
+ hmac_final
+ },
+};
+
+struct hash *
+hash_get(enum hashes hashtype)
+{
+ size_t i;
+
+ LOG_DBG((LOG_CRYPTO, 60, "hash_get: requested algorithm %d",
+ hashtype));
+
+ for (i = 0; i < sizeof hashes / sizeof hashes[0]; i++)
+ if (hashtype == hashes[i].type)
+ return &hashes[i];
+
+ return 0;
+}
+
+/*
+ * Initial a hash for HMAC usage this requires a special init function.
+ * ctx, ctx2 hold the contexts, if you want to use the hash object for
+ * something else in the meantime, be sure to store the contexts somewhere.
+ */
+
+void
+hmac_init(struct hash *hash, unsigned char *okey, unsigned int len)
+{
+ unsigned int i, blocklen = HMAC_BLOCKLEN;
+ unsigned char key[HMAC_BLOCKLEN];
+
+ memset(key, 0, blocklen);
+ if (len > blocklen) {
+ /* Truncate key down to blocklen */
+ hash->Init(hash->ctx);
+ hash->Update(hash->ctx, okey, len);
+ hash->Final(key, hash->ctx);
+ } else {
+ memcpy(key, okey, len);
+ }
+
+ /* HMAC I and O pad computation */
+ for (i = 0; i < blocklen; i++)
+ key[i] ^= HMAC_IPAD_VAL;
+
+ hash->Init(hash->ctx);
+ hash->Update(hash->ctx, key, blocklen);
+
+ for (i = 0; i < blocklen; i++)
+ key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
+
+ hash->Init(hash->ctx2);
+ hash->Update(hash->ctx2, key, blocklen);
+
+ memset(key, 0, blocklen);
+}
+
+/*
+ * HMAC Final function
+ */
+
+void
+hmac_final(unsigned char *dgst, struct hash *hash)
+{
+ hash->Final(dgst, hash->ctx);
+ hash->Update(hash->ctx2, dgst, hash->hashsize);
+ hash->Final(dgst, hash->ctx2);
+}
diff --git a/keyexchange/isakmpd-20041012/hash.h b/keyexchange/isakmpd-20041012/hash.h
new file mode 100644
index 0000000..3af2350
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/hash.h
@@ -0,0 +1,70 @@
+/* $OpenBSD: hash.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: hash.h,v 1.6 1998/07/25 22:04:36 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _HASH_H_
+#define _HASH_H_
+
+/* Normal mode hash encapsulation */
+
+#define MD5_SIZE 16
+#define SHA1_SIZE 20
+#define HASH_MAX SHA1_SIZE
+
+enum hashes {
+ HASH_MD5 = 0,
+ HASH_SHA1
+};
+
+struct hash {
+ enum hashes type;
+ int id; /* ISAKMP/Oakley ID */
+ u_int8_t hashsize; /* Size of the hash */
+ void *ctx; /* Pointer to a context, for HMAC ictx */
+ unsigned char *digest; /* Pointer to a digest */
+ int ctxsize;
+ void *ctx2; /* Pointer to a 2nd context, for HMAC octx */
+ void (*Init) (void *);
+ void (*Update) (void *, unsigned char *, unsigned int);
+ void (*Final) (unsigned char *, void *);
+ void (*HMACInit) (struct hash *, unsigned char *, unsigned int);
+ void (*HMACFinal) (unsigned char *, struct hash *);
+};
+
+/* HMAC Hash Encapsulation */
+
+#define HMAC_IPAD_VAL 0x36
+#define HMAC_OPAD_VAL 0x5C
+#define HMAC_BLOCKLEN 64
+
+extern struct hash *hash_get(enum hashes);
+extern void hmac_init(struct hash *, unsigned char *, unsigned int);
+
+#endif /* _HASH_H_ */
diff --git a/keyexchange/isakmpd-20041012/if.c b/keyexchange/isakmpd-20041012/if.c
new file mode 100644
index 0000000..b9cf927
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/if.c
@@ -0,0 +1,152 @@
+/* $OpenBSD: if.c,v 1.22 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: if.c,v 1.12 1999/10/01 13:45:20 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#endif
+
+#include "sysdep.h"
+
+#include "log.h"
+#include "monitor.h"
+#include "if.h"
+
+#ifndef HAVE_GETIFADDRS
+/* XXX Unsafe if either x or y has side-effects. */
+#ifndef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+/* Most boxes has less than 16 interfaces, so this might be a good guess. */
+#define INITIAL_IFREQ_COUNT 16
+
+/*
+ * Get all network interface configurations.
+ * Return 0 if successful, -1 otherwise.
+ */
+int
+siocgifconf(struct ifconf *ifcp)
+{
+ caddr_t buf, new_buf;
+ int s, len;
+
+ /* Get a socket to ask for the network interface configurations. */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1) {
+ log_error("siocgifconf: "
+ "socket (AF_INET, SOCK_DGRAM, 0) failed");
+ return -1;
+ }
+ len = sizeof(struct ifreq) * INITIAL_IFREQ_COUNT;
+ buf = 0;
+ while (1) {
+ /*
+ * Allocate a larger buffer each time around the loop and get
+ * the network interfaces configurations into it.
+ */
+ new_buf = realloc(buf, len);
+ if (!new_buf) {
+ log_error("siocgifconf: realloc (%p, %d) failed", buf,
+ len);
+ goto err;
+ }
+ ifcp->ifc_len = len;
+ ifcp->ifc_buf = buf = new_buf;
+ if (ioctl(s, SIOCGIFCONF, ifcp) == -1) {
+ log_error("siocgifconf: ioctl (%d, SIOCGIFCONF, ...) "
+ "failed", s);
+ goto err;
+ }
+
+ /*
+ * If there is place for another ifreq we can be sure that the
+ * buffer was big enough, otherwise double the size and try
+ * again.
+ */
+ if (len - ifcp->ifc_len >= sizeof(struct ifreq))
+ break;
+ len *= 2;
+ }
+ close(s);
+ return 0;
+
+err:
+ if (buf)
+ free(buf);
+ ifcp->ifc_len = 0;
+ ifcp->ifc_buf = 0;
+ close(s);
+ return -1;
+}
+#endif
+
+int
+if_map(int (*func)(char *, struct sockaddr *, void *), void *arg)
+{
+ int err = 0;
+
+#ifdef HAVE_GETIFADDRS
+ struct ifaddrs *ifap, *ifa;
+
+ if (getifaddrs(&ifap) < 0)
+ return -1;
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next)
+ if ((*func)(ifa->ifa_name, ifa->ifa_addr, arg) == -1)
+ err = -1;
+ freeifaddrs(ifap);
+#else
+ struct ifconf ifc;
+ struct ifreq *ifrp;
+ caddr_t limit, p;
+ size_t len;
+
+ if (siocgifconf(&ifc))
+ return -1;
+
+ limit = ifc.ifc_buf + ifc.ifc_len;
+ for (p = ifc.ifc_buf; p < limit; p += len) {
+ ifrp = (struct ifreq *)p;
+ if ((*func)(ifrp->ifr_name, &ifrp->ifr_addr, arg) == -1)
+ err = -1;
+ len = sizeof ifrp->ifr_name +
+ MAX(sysdep_sa_len(&ifrp->ifr_addr), sizeof ifrp->ifr_addr);
+ }
+ free(ifc.ifc_buf);
+#endif
+ return err;
+}
diff --git a/keyexchange/isakmpd-20041012/if.h b/keyexchange/isakmpd-20041012/if.h
new file mode 100644
index 0000000..82d574d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/if.h
@@ -0,0 +1,43 @@
+/* $OpenBSD: if.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: if.h,v 1.2 1998/07/07 23:35:58 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IF_H_
+#define _IF_H_
+
+#include <sys/types.h>
+
+struct ifreq;
+struct ifconf;
+
+extern int if_map(int (*) (char *, struct sockaddr *, void *), void *);
+extern int siocgifconf(struct ifconf *);
+
+#endif /* _IF_H_ */
diff --git a/keyexchange/isakmpd-20041012/ike_aggressive.c b/keyexchange/isakmpd-20041012/ike_aggressive.c
new file mode 100644
index 0000000..48ec10f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_aggressive.c
@@ -0,0 +1,184 @@
+/* $OpenBSD: ike_aggressive.c,v 1.8 2004/07/29 08:54:08 ho Exp $ */
+/* $EOM: ike_aggressive.c,v 1.4 2000/01/31 22:33:45 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999 Angelos D. Keromytis. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "conf.h"
+#include "constants.h"
+#include "crypto.h"
+#include "dh.h"
+#include "doi.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "ike_aggressive.h"
+#include "ike_phase_1.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "isakmp.h"
+#include "log.h"
+#include "math_group.h"
+#include "message.h"
+#if defined (USE_NAT_TRAVERSAL)
+#include "nat_traversal.h"
+#endif
+#include "prf.h"
+#include "sa.h"
+#include "transport.h"
+#include "util.h"
+
+static int initiator_recv_SA_KE_NONCE_ID_AUTH(struct message *);
+static int initiator_send_SA_KE_NONCE_ID(struct message *);
+static int initiator_send_AUTH(struct message *);
+static int responder_recv_SA_KE_NONCE_ID(struct message *);
+static int responder_send_SA_KE_NONCE_ID_AUTH(struct message *);
+static int responder_recv_AUTH(struct message *);
+
+int (*ike_aggressive_initiator[])(struct message *) = {
+ initiator_send_SA_KE_NONCE_ID,
+ initiator_recv_SA_KE_NONCE_ID_AUTH,
+ initiator_send_AUTH
+};
+
+int (*ike_aggressive_responder[])(struct message *) = {
+ responder_recv_SA_KE_NONCE_ID,
+ responder_send_SA_KE_NONCE_ID_AUTH,
+ responder_recv_AUTH
+};
+
+/* Offer a set of transforms to the responder in the MSG message. */
+static int
+initiator_send_SA_KE_NONCE_ID(struct message *msg)
+{
+ if (ike_phase_1_initiator_send_SA(msg))
+ return -1;
+
+ if (ike_phase_1_initiator_send_KE_NONCE(msg))
+ return -1;
+
+ return ike_phase_1_send_ID(msg);
+}
+
+/* Figure out what transform the responder chose. */
+static int
+initiator_recv_SA_KE_NONCE_ID_AUTH(struct message *msg)
+{
+ if (ike_phase_1_initiator_recv_SA(msg))
+ return -1;
+
+ if (ike_phase_1_initiator_recv_KE_NONCE(msg))
+ return -1;
+
+ return ike_phase_1_recv_ID_AUTH(msg);
+}
+
+static int
+initiator_send_AUTH(struct message *msg)
+{
+ msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+
+ if (ike_phase_1_send_AUTH(msg))
+ return -1;
+
+ /*
+ * RFC 2407 4.6.3 says that, among others, INITIAL-CONTACT MUST NOT
+ * be sent in Aggressive Mode. This leaves us with the choice of
+ * doing it in an informational exchange of its own with no delivery
+ * guarantee or in the first Quick Mode, or not at all.
+ * draft-jenkins-ipsec-rekeying-01.txt has some text that requires
+ * INITIAL-CONTACT in phase 1, thus contradicting what we learned
+ * above. I will bring this up in the IPsec list. For now we don't
+ * do INITIAL-CONTACT at all when using aggressive mode.
+ */
+ return 0;
+}
+
+/*
+ * Accept a set of transforms offered by the initiator and chose one we can
+ * handle. Also accept initiator's public DH value, nonce and ID.
+ */
+static int
+responder_recv_SA_KE_NONCE_ID(struct message *msg)
+{
+ if (ike_phase_1_responder_recv_SA(msg))
+ return -1;
+
+ if (ike_phase_1_recv_ID(msg))
+ return -1;
+
+ return ike_phase_1_recv_KE_NONCE(msg);
+}
+
+/*
+ * Reply with the transform we chose. Send our public DH value and a nonce
+ * to the initiator.
+ */
+static int
+responder_send_SA_KE_NONCE_ID_AUTH(struct message *msg)
+{
+ /* Add the SA payload with the transform that was chosen. */
+ if (ike_phase_1_responder_send_SA(msg))
+ return -1;
+
+ /* XXX Should we really just use the initiator's nonce size? */
+ if (ike_phase_1_send_KE_NONCE(msg, msg->exchange->nonce_i_len))
+ return -1;
+
+ if (ike_phase_1_post_exchange_KE_NONCE(msg))
+ return -1;
+
+ return ike_phase_1_responder_send_ID_AUTH(msg);
+}
+
+/*
+ * Reply with the transform we chose. Send our public DH value and a nonce
+ * to the initiator.
+ */
+static int
+responder_recv_AUTH(struct message *msg)
+{
+ if (ike_phase_1_recv_AUTH(msg))
+ return -1;
+
+#if defined (USE_NAT_TRAVERSAL)
+ /* Aggressive: Check for NAT-D payloads and contents. */
+ if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER)
+ (void)nat_t_exchange_check_nat_d(msg);
+#endif
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/ike_aggressive.h b/keyexchange/isakmpd-20041012/ike_aggressive.h
new file mode 100644
index 0000000..f2af524
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_aggressive.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: ike_aggressive.h,v 1.5 2004/05/23 18:17:55 hshoexer Exp $ */
+/* $EOM: ike_aggressive.h,v 1.1 1999/04/16 21:24:43 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IKE_AGGRESSIVE_H_
+#define _IKE_AGGRESSIVE_H_
+
+struct message;
+
+extern int (*ike_aggressive_initiator[])(struct message *msg);
+extern int (*ike_aggressive_responder[])(struct message *msg);
+
+#endif /* _IKE_AGGRESSIVE_H_ */
diff --git a/keyexchange/isakmpd-20041012/ike_auth.c b/keyexchange/isakmpd-20041012/ike_auth.c
new file mode 100644
index 0000000..dcacb0e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_auth.c
@@ -0,0 +1,1167 @@
+/* $OpenBSD: ike_auth.c,v 1.95 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: ike_auth.c,v 1.59 2000/11/21 00:21:31 angelos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <regex.h>
+#if defined (USE_KEYNOTE)
+#include <keynote.h>
+#endif
+#include <policy.h>
+
+#include "sysdep.h"
+
+#include "cert.h"
+#include "conf.h"
+#include "constants.h"
+#if defined (USE_DNSSEC)
+#include "dnssec.h"
+#endif
+#include "exchange.h"
+#include "gmp_util.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "libcrypto.h"
+#include "log.h"
+#include "message.h"
+#include "monitor.h"
+#include "prf.h"
+#include "transport.h"
+#include "util.h"
+#include "key.h"
+#if defined (USE_X509)
+#include "x509.h"
+#endif
+
+#ifdef notyet
+static u_int8_t *enc_gen_skeyid(struct exchange *, size_t *);
+#endif
+static u_int8_t *pre_shared_gen_skeyid(struct exchange *, size_t *);
+
+static int pre_shared_decode_hash(struct message *);
+static int pre_shared_encode_hash(struct message *);
+
+#if defined (USE_X509) || defined (USE_KEYNOTE)
+static u_int8_t *sig_gen_skeyid(struct exchange *, size_t *);
+static int rsa_sig_decode_hash(struct message *);
+static int rsa_sig_encode_hash(struct message *);
+#endif
+
+#if defined (USE_RAWKEY)
+static int get_raw_key_from_file(int, u_int8_t *, size_t, RSA **);
+#endif
+
+static int ike_auth_hash(struct exchange *, u_int8_t *);
+
+static struct ike_auth ike_auth[] = {
+ {
+ IKE_AUTH_PRE_SHARED, pre_shared_gen_skeyid,
+ pre_shared_decode_hash,
+ pre_shared_encode_hash
+ },
+#ifdef notdef
+ {
+ IKE_AUTH_DSS, sig_gen_skeyid,
+ pre_shared_decode_hash,
+ pre_shared_encode_hash
+ },
+#endif
+#if defined (USE_X509) || defined (USE_KEYNOTE)
+ {
+ IKE_AUTH_RSA_SIG, sig_gen_skeyid,
+ rsa_sig_decode_hash,
+ rsa_sig_encode_hash
+ },
+#endif
+#ifdef notdef
+ {
+ IKE_AUTH_RSA_ENC, enc_gen_skeyid,
+ pre_shared_decode_hash,
+ pre_shared_encode_hash
+ },
+ {
+ IKE_AUTH_RSA_ENC_REV, enc_gen_skeyid,
+ pre_shared_decode_hash,
+ pre_shared_encode_hash
+ },
+#endif
+};
+
+struct ike_auth *
+ike_auth_get(u_int16_t id)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof ike_auth / sizeof ike_auth[0]; i++)
+ if (id == ike_auth[i].id)
+ return &ike_auth[i];
+ return 0;
+}
+
+/*
+ * Find and decode the configured key (pre-shared or public) for the
+ * peer denoted by ID. Stash the len in KEYLEN.
+ */
+static void *
+ike_auth_get_key(int type, char *id, char *local_id, size_t *keylen)
+{
+ char *key, *buf;
+#if defined (USE_X509) || defined (USE_KEYNOTE)
+ int fd;
+ char *keyfile;
+#if defined (USE_X509)
+ FILE *keyfp;
+ RSA *rsakey;
+ size_t fsize;
+#endif
+#endif
+
+ switch (type) {
+ case IKE_AUTH_PRE_SHARED:
+ /* Get the pre-shared key for our peer. */
+ key = conf_get_str(id, "Authentication");
+ if (!key && local_id)
+ key = conf_get_str(local_id, "Authentication");
+
+ if (!key) {
+ log_print("ike_auth_get_key: "
+ "no key found for peer \"%s\" or local ID \"%s\"",
+ id, local_id);
+ return 0;
+ }
+ /* If the key starts with 0x it is in hex format. */
+ if (strncasecmp(key, "0x", 2) == 0) {
+ *keylen = (strlen(key) - 1) / 2;
+ buf = malloc(*keylen);
+ if (!buf) {
+ log_error("ike_auth_get_key: malloc (%lu) "
+ "failed", (unsigned long)*keylen);
+ return 0;
+ }
+ if (hex2raw(key + 2, (unsigned char *)buf, *keylen)) {
+ free(buf);
+ log_print("ike_auth_get_key: invalid hex key "
+ "%s", key);
+ return 0;
+ }
+ key = buf;
+ } else {
+ buf = key;
+ key = strdup(buf);
+ if (!key) {
+ log_error("ike_auth_get_key: strdup() failed");
+ return 0;
+ }
+ *keylen = strlen(key);
+ }
+ break;
+
+ case IKE_AUTH_RSA_SIG:
+#if defined (USE_X509) || defined (USE_KEYNOTE)
+#if defined (USE_KEYNOTE)
+ if (local_id && (keyfile = conf_get_str("KeyNote",
+ "Credential-directory")) != 0) {
+ struct stat sb;
+ struct keynote_deckey dc;
+ char *privkeyfile, *buf2;
+ int pkflen;
+ size_t size;
+
+ pkflen = strlen(keyfile) + strlen(local_id) +
+ sizeof PRIVATE_KEY_FILE + sizeof "//" - 1;
+ privkeyfile = calloc(pkflen, sizeof(char));
+ if (!privkeyfile) {
+ log_print("ike_auth_get_key: failed to "
+ "allocate %d bytes", pkflen);
+ return 0;
+ }
+ snprintf(privkeyfile, pkflen, "%s/%s/%s", keyfile,
+ local_id, PRIVATE_KEY_FILE);
+ keyfile = privkeyfile;
+
+ fd = monitor_open(keyfile, O_RDONLY, 0);
+ if (fd < 0) {
+ free(keyfile);
+ goto ignorekeynote;
+ }
+
+ if (fstat(fd, &sb) < 0) {
+ log_print("ike_auth_get_key: fstat failed");
+ free(keyfile);
+ close(fd);
+ return 0;
+ }
+ size = (size_t)sb.st_size;
+
+ buf = calloc(size + 1, sizeof(char));
+ if (!buf) {
+ log_print("ike_auth_get_key: failed allocating"
+ " %lu bytes", (unsigned long)size + 1);
+ free(keyfile);
+ close(fd);
+ return 0;
+ }
+ if (read(fd, buf, size) != (ssize_t)size) {
+ free(buf);
+ log_print("ike_auth_get_key: "
+ "failed reading %lu bytes from \"%s\"",
+ (unsigned long)size, keyfile);
+ free(keyfile);
+ close(fd);
+ return 0;
+ }
+ close(fd);
+
+ /* Parse private key string */
+ buf2 = kn_get_string(buf);
+ free(buf);
+
+ if (!buf2 || kn_decode_key(&dc, buf2,
+ KEYNOTE_PRIVATE_KEY) == -1) {
+ if (buf2)
+ free(buf2);
+ log_print("ike_auth_get_key: failed decoding "
+ "key in \"%s\"", keyfile);
+ free(keyfile);
+ return 0;
+ }
+ free(buf2);
+
+ if (dc.dec_algorithm != KEYNOTE_ALGORITHM_RSA) {
+ log_print("ike_auth_get_key: wrong algorithm "
+ "type %d in \"%s\"", dc.dec_algorithm,
+ keyfile);
+ free(keyfile);
+ kn_free_key(&dc);
+ return 0;
+ }
+ free(keyfile);
+ return dc.dec_key;
+ }
+ignorekeynote:
+#endif /* USE_KEYNOTE */
+#ifdef USE_X509
+ /* Otherwise, try X.509 */
+ keyfile = conf_get_str("X509-certificates", "Private-key");
+
+ fd = monitor_open(keyfile, O_RDONLY, 0);
+ if (fd < 0) {
+ log_print("ike_auth_get_key: failed opening \"%s\"",
+ keyfile);
+ return 0;
+ }
+
+ if (check_file_secrecy_fd(fd, keyfile, &fsize) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ if ((keyfp = fdopen(fd, "r")) == NULL) {
+ log_print("ike_auth_get_key: fdopen failed");
+ close(fd);
+ return 0;
+ }
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ rsakey = PEM_read_RSAPrivateKey(keyfp, NULL, NULL, NULL);
+#else
+ rsakey = PEM_read_RSAPrivateKey(keyfp, NULL, NULL);
+#endif
+ fclose(keyfp);
+
+ if (!rsakey) {
+ log_print("ike_auth_get_key: "
+ "PEM_read_bio_RSAPrivateKey failed");
+ return 0;
+ }
+ return rsakey;
+#endif /* USE_X509 */
+#endif /* USE_X509 || USE_KEYNOTE */
+
+ default:
+ log_print("ike_auth_get_key: unknown key type %d", type);
+ return 0;
+ }
+
+ return key;
+}
+
+static u_int8_t *
+pre_shared_gen_skeyid(struct exchange *exchange, size_t *sz)
+{
+ struct prf *prf;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t *skeyid, *buf = 0;
+ unsigned char *key;
+ size_t keylen;
+
+ /*
+ * If we're the responder and have the initiator's ID (which is the
+ * case in Aggressive mode), try to find the preshared key in the
+ * section of the initiator's Phase 1 ID. This allows us to do
+ * mobile user support with preshared keys.
+ */
+ if (!exchange->initiator && exchange->id_i) {
+ switch (exchange->id_i[0]) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV6_ADDR:
+ util_ntoa((char **) &buf,
+ exchange->id_i[0] == IPSEC_ID_IPV4_ADDR ? AF_INET :
+ AF_INET6, exchange->id_i + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ);
+ if (!buf)
+ return 0;
+ break;
+
+ case IPSEC_ID_FQDN:
+ case IPSEC_ID_USER_FQDN:
+ buf = calloc(exchange->id_i_len - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ + 1, sizeof(char));
+ if (!buf) {
+ log_print("pre_shared_gen_skeyid: malloc (%lu"
+ ") failed",
+ (unsigned long)exchange->id_i_len -
+ ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1);
+ return 0;
+ }
+ memcpy(buf,
+ exchange->id_i + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ,
+ exchange->id_i_len - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ);
+ break;
+
+ /* XXX Support more ID types ? */
+ default:
+ break;
+ }
+ }
+ /*
+ * Get the pre-shared key for our peer. This will work even if the key
+ * has been passed to us through a mechanism like PFKEYv2.
+ */
+ key = ike_auth_get_key(IKE_AUTH_PRE_SHARED, exchange->name,
+ (char *) buf, &keylen);
+ if (buf)
+ free(buf);
+
+ /* Fail if no key could be found. */
+ if (!key)
+ return 0;
+
+ /* Store the secret key for later policy processing. */
+ exchange->recv_key = calloc(keylen + 1, sizeof(char));
+ exchange->recv_keytype = ISAKMP_KEY_PASSPHRASE;
+ if (!exchange->recv_key) {
+ log_error("pre_shared_gen_skeyid: malloc (%lu) failed",
+ (unsigned long)keylen);
+ free(key);
+ return 0;
+ }
+ memcpy(exchange->recv_key, key, keylen);
+ exchange->recv_certtype = ISAKMP_CERTENC_NONE;
+ free(key);
+
+ prf = prf_alloc(ie->prf_type, ie->hash->type, exchange->recv_key,
+ keylen);
+ if (!prf)
+ return 0;
+
+ *sz = prf->blocksize;
+ skeyid = malloc(*sz);
+ if (!skeyid) {
+ log_error("pre_shared_gen_skeyid: malloc (%lu) failed",
+ (unsigned long)*sz);
+ prf_free(prf);
+ return 0;
+ }
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+ prf->Update(prf->prfctx, exchange->nonce_r, exchange->nonce_r_len);
+ prf->Final(skeyid, prf->prfctx);
+ prf_free(prf);
+ return skeyid;
+}
+
+#if defined (USE_X509) || defined (USE_KEYNOTE)
+/* Both DSS & RSA signature authentication use this algorithm. */
+static u_int8_t *
+sig_gen_skeyid(struct exchange *exchange, size_t *sz)
+{
+ struct prf *prf;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t *skeyid;
+ unsigned char *key;
+
+ key = malloc(exchange->nonce_i_len + exchange->nonce_r_len);
+ if (!key)
+ return 0;
+ memcpy(key, exchange->nonce_i, exchange->nonce_i_len);
+ memcpy(key + exchange->nonce_i_len, exchange->nonce_r,
+ exchange->nonce_r_len);
+
+ LOG_DBG((LOG_NEGOTIATION, 80, "sig_gen_skeyid: PRF type %d, hash %d",
+ ie->prf_type, ie->hash->type));
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80,
+ "sig_gen_skeyid: SKEYID initialized with",
+ (u_int8_t *)key, exchange->nonce_i_len + exchange->nonce_r_len));
+
+ prf = prf_alloc(ie->prf_type, ie->hash->type, key,
+ exchange->nonce_i_len + exchange->nonce_r_len);
+ free(key);
+ if (!prf)
+ return 0;
+
+ *sz = prf->blocksize;
+ skeyid = malloc(*sz);
+ if (!skeyid) {
+ log_error("sig_gen_skeyid: malloc (%lu) failed",
+ (unsigned long)*sz);
+ prf_free(prf);
+ return 0;
+ }
+ LOG_DBG((LOG_NEGOTIATION, 80, "sig_gen_skeyid: g^xy length %lu",
+ (unsigned long) ie->g_x_len));
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80,
+ "sig_gen_skeyid: SKEYID fed with g^xy", ie->g_xy, ie->g_x_len));
+
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len);
+ prf->Final(skeyid, prf->prfctx);
+ prf_free(prf);
+ return skeyid;
+}
+#endif /* USE_X509 || USE_KEYNOTE */
+
+#ifdef notdef
+/*
+ * Both standard and revised RSA encryption authentication use this SKEYID
+ * computation.
+ */
+static u_int8_t *
+enc_gen_skeyid(struct exchange *exchange, size_t *sz)
+{
+ struct prf *prf;
+ struct ipsec_exch *ie = exchange->data;
+ struct hash *hash = ie->hash;
+ u_int8_t *skeyid;
+
+ hash->Init(hash->ctx);
+ hash->Update(hash->ctx, exchange->nonce_i, exchange->nonce_i_len);
+ hash->Update(hash->ctx, exchange->nonce_r, exchange->nonce_r_len);
+ hash->Final(hash->digest, hash->ctx);
+ prf = prf_alloc(ie->prf_type, hash->type, hash->digest, *sz);
+ if (!prf)
+ return 0;
+
+ *sz = prf->blocksize;
+ skeyid = malloc(*sz);
+ if (!skeyid) {
+ log_error("enc_gen_skeyid: malloc (%d) failed", *sz);
+ prf_free(prf);
+ return 0;
+ }
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Final(skeyid, prf->prfctx);
+ prf_free(prf);
+ return skeyid;
+}
+#endif /* notdef */
+
+static int
+pre_shared_decode_hash(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct payload *payload;
+ size_t hashsize = ie->hash->hashsize;
+ char header[80];
+ int initiator = exchange->initiator;
+ u_int8_t **hash_p;
+
+ /* Choose the right fields to fill-in. */
+ hash_p = initiator ? &ie->hash_r : &ie->hash_i;
+
+ payload = payload_first(msg, ISAKMP_PAYLOAD_HASH);
+ if (!payload) {
+ log_print("pre_shared_decode_hash: no HASH payload found");
+ return -1;
+ }
+ /* Check that the hash is of the correct size. */
+ if (GET_ISAKMP_GEN_LENGTH(payload->p) - ISAKMP_GEN_SZ != hashsize)
+ return -1;
+
+ /* XXX Need this hash be in the SA? */
+ *hash_p = malloc(hashsize);
+ if (!*hash_p) {
+ log_error("pre_shared_decode_hash: malloc (%lu) failed",
+ (unsigned long)hashsize);
+ return -1;
+ }
+ memcpy(*hash_p, payload->p + ISAKMP_HASH_DATA_OFF, hashsize);
+ snprintf(header, sizeof header, "pre_shared_decode_hash: HASH_%c",
+ initiator ? 'R' : 'I');
+ LOG_DBG_BUF((LOG_MISC, 80, header, *hash_p, hashsize));
+
+ payload->flags |= PL_MARK;
+ return 0;
+}
+
+#if defined (USE_X509) || defined (USE_KEYNOTE)
+/* Decrypt the HASH in SIG, we already need a parsed ID payload. */
+static int
+rsa_sig_decode_hash(struct message *msg)
+{
+ struct cert_handler *handler;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct payload *p;
+ void *cert = 0;
+ u_int8_t *rawcert = 0, **hash_p, **id_cert, *id;
+ u_int32_t rawcertlen, *id_cert_len;
+ RSA *key = 0;
+ size_t hashsize = ie->hash->hashsize, id_len;
+ char header[80];
+ int len, initiator = exchange->initiator;
+ int found = 0, n, i, id_found;
+#if defined (USE_DNSSEC)
+ u_int8_t *rawkey = 0;
+ u_int32_t rawkeylen;
+#endif
+
+ /* Choose the right fields to fill-in. */
+ hash_p = initiator ? &ie->hash_r : &ie->hash_i;
+ id = initiator ? exchange->id_r : exchange->id_i;
+ id_len = initiator ? exchange->id_r_len : exchange->id_i_len;
+
+ if (!id || id_len == 0) {
+ log_print("rsa_sig_decode_hash: ID is missing");
+ return -1;
+ }
+ /*
+ * XXX Assume we should use the same kind of certification as the
+ * remote... moreover, just use the first CERT payload to decide what
+ * to use.
+ */
+ p = payload_first(msg, ISAKMP_PAYLOAD_CERT);
+ if (!p)
+ handler = cert_get(ISAKMP_CERTENC_KEYNOTE);
+ else
+ handler = cert_get(GET_ISAKMP_CERT_ENCODING(p->p));
+ if (!handler) {
+ log_print("rsa_sig_decode_hash: cert_get (%d) failed",
+ p ? GET_ISAKMP_CERT_ENCODING(p->p) : -1);
+ return -1;
+ }
+#if defined (USE_POLICY) || defined (USE_KEYNOTE)
+ /*
+ * We need the policy session initialized now, so we can add
+ * credentials etc.
+ */
+ exchange->policy_id = kn_init();
+ if (exchange->policy_id == -1) {
+ log_print("rsa_sig_decode_hash: failed to initialize policy "
+ "session");
+ return -1;
+ }
+#endif /* USE_POLICY || USE_KEYNOTE */
+
+ /* Obtain a certificate from our certificate storage. */
+ if (handler->cert_obtain(id, id_len, 0, &rawcert, &rawcertlen)) {
+ if (handler->id == ISAKMP_CERTENC_X509_SIG) {
+ cert = handler->cert_get(rawcert, rawcertlen);
+ if (!cert)
+ LOG_DBG((LOG_CRYPTO, 50, "rsa_sig_decode_hash:"
+ " certificate malformed"));
+ else {
+ if (!handler->cert_get_key(cert, &key)) {
+ log_print("rsa_sig_decode_hash: "
+ "decoding certificate failed");
+ handler->cert_free(cert);
+ } else {
+ found++;
+ LOG_DBG((LOG_CRYPTO, 40,
+ "rsa_sig_decode_hash: using cert "
+ "of type %d", handler->id));
+ exchange->recv_cert = cert;
+ exchange->recv_certtype = handler->id;
+#if defined (USE_POLICY)
+ x509_generate_kn(exchange->policy_id,
+ cert);
+#endif /* USE_POLICY */
+ }
+ }
+ } else if (handler->id == ISAKMP_CERTENC_KEYNOTE)
+ handler->cert_insert(exchange->policy_id, rawcert);
+ free(rawcert);
+ }
+ /*
+ * Walk over potential CERT payloads in this message.
+ * XXX I believe this is the wrong spot for this. CERTs can appear
+ * anytime.
+ */
+ for (p = payload_first(msg, ISAKMP_PAYLOAD_CERT); p;
+ p = TAILQ_NEXT(p, link)) {
+ p->flags |= PL_MARK;
+
+ /*
+ * When we have found a key, just walk over the rest, marking
+ * them.
+ */
+ if (found)
+ continue;
+
+ handler = cert_get(GET_ISAKMP_CERT_ENCODING(p->p));
+ if (!handler) {
+ LOG_DBG((LOG_MISC, 30, "rsa_sig_decode_hash: "
+ "no handler for %s CERT encoding",
+ constant_name(isakmp_certenc_cst,
+ GET_ISAKMP_CERT_ENCODING(p->p))));
+ continue;
+ }
+ cert = handler->cert_get(p->p + ISAKMP_CERT_DATA_OFF,
+ GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_CERT_DATA_OFF);
+ if (!cert) {
+ log_print("rsa_sig_decode_hash: "
+ "can not get data from CERT");
+ continue;
+ }
+ if (!handler->cert_validate(cert)) {
+ handler->cert_free(cert);
+ log_print("rsa_sig_decode_hash: received CERT can't "
+ "be validated");
+ continue;
+ }
+ if (GET_ISAKMP_CERT_ENCODING(p->p) ==
+ ISAKMP_CERTENC_X509_SIG) {
+ if (!handler->cert_get_subjects(cert, &n, &id_cert,
+ &id_cert_len)) {
+ handler->cert_free(cert);
+ log_print("rsa_sig_decode_hash: can not get "
+ "subject from CERT");
+ continue;
+ }
+ id_found = 0;
+ for (i = 0; i < n; i++)
+ if (id_cert_len[i] == id_len &&
+ id[0] == id_cert[i][0] &&
+ memcmp(id + 4, id_cert[i] + 4, id_len - 4)
+ == 0) {
+ id_found++;
+ break;
+ }
+ if (!id_found) {
+ handler->cert_free(cert);
+ log_print("rsa_sig_decode_hash: no CERT "
+ "subject match the ID");
+ free(id_cert);
+ continue;
+ }
+ cert_free_subjects(n, id_cert, id_cert_len);
+ }
+ if (!handler->cert_get_key(cert, &key)) {
+ handler->cert_free(cert);
+ log_print("rsa_sig_decode_hash: decoding payload CERT "
+ "failed");
+ continue;
+ }
+ /* We validated the cert, cache it for later use. */
+ handler->cert_insert(exchange->policy_id, cert);
+
+ exchange->recv_cert = cert;
+ exchange->recv_certtype = GET_ISAKMP_CERT_ENCODING(p->p);
+
+#if defined (USE_POLICY) || defined (USE_KEYNOTE)
+ if (exchange->recv_certtype == ISAKMP_CERTENC_KEYNOTE) {
+ struct keynote_deckey dc;
+ char *pp;
+ int dclen;
+
+ dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
+ dc.dec_key = key;
+
+ pp = kn_encode_key(&dc, INTERNAL_ENC_PKCS1,
+ ENCODING_HEX, KEYNOTE_PUBLIC_KEY);
+ if (pp == NULL) {
+ kn_free_key(&dc);
+ log_print("rsa_sig_decode_hash: failed to "
+ "ASCII-encode key");
+ return -1;
+ }
+ dclen = strlen(pp) + sizeof "rsa-hex:";
+ exchange->keynote_key = calloc(dclen, sizeof(char));
+ if (!exchange->keynote_key) {
+ free(pp);
+ kn_free_key(&dc);
+ log_print("rsa_sig_decode_hash: failed to "
+ "allocate %d bytes", dclen);
+ return -1;
+ }
+ snprintf(exchange->keynote_key, dclen, "rsa-hex:%s",
+ pp);
+ free(pp);
+ }
+#endif
+
+ found++;
+ }
+
+#if defined (USE_DNSSEC)
+ /*
+ * If no certificate provided a key, try to find a validated DNSSEC
+ * KEY.
+ */
+ if (!found) {
+ rawkey = dns_get_key(IKE_AUTH_RSA_SIG, msg, &rawkeylen);
+
+ /* We need to convert 'void *rawkey' into 'RSA *key'. */
+ if (dns_RSA_dns_to_x509(rawkey, rawkeylen, &key) == 0)
+ found++;
+ else
+ log_print("rsa_sig_decode_hash: KEY to RSA key "
+ "conversion failed");
+
+ if (rawkey)
+ free(rawkey);
+ }
+#endif /* USE_DNSSEC */
+
+#if defined (USE_RAWKEY)
+ /* If we still have not found a key, try to read it from a file. */
+ if (!found)
+ if (get_raw_key_from_file(IKE_AUTH_RSA_SIG, id, id_len, &key)
+ != -1)
+ found++;
+#endif
+
+ if (!found) {
+ log_print("rsa_sig_decode_hash: no public key found");
+ return -1;
+ }
+ p = payload_first(msg, ISAKMP_PAYLOAD_SIG);
+ if (!p) {
+ log_print("rsa_sig_decode_hash: missing signature payload");
+ RSA_free(key);
+ return -1;
+ }
+ /* Check that the sig is of the correct size. */
+ len = GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_SIG_SZ;
+ if (len != RSA_size(key)) {
+ RSA_free(key);
+ log_print("rsa_sig_decode_hash: "
+ "SIG payload length does not match public key");
+ return -1;
+ }
+ *hash_p = malloc(len);
+ if (!*hash_p) {
+ RSA_free(key);
+ log_error("rsa_sig_decode_hash: malloc (%d) failed", len);
+ return -1;
+ }
+ len = RSA_public_decrypt(len, p->p + ISAKMP_SIG_DATA_OFF, *hash_p, key,
+ RSA_PKCS1_PADDING);
+ if (len == -1) {
+ RSA_free(key);
+ log_print("rsa_sig_decode_hash: RSA_public_decrypt () failed");
+ return -1;
+ }
+ /* Store key for later use */
+ exchange->recv_key = key;
+ exchange->recv_keytype = ISAKMP_KEY_RSA;
+
+ if (len != (int) hashsize) {
+ free(*hash_p);
+ *hash_p = 0;
+ log_print("rsa_sig_decode_hash: len %lu != hashsize %lu",
+ (unsigned long)len, (unsigned long)hashsize);
+ return -1;
+ }
+ snprintf(header, sizeof header, "rsa_sig_decode_hash: HASH_%c",
+ initiator ? 'R' : 'I');
+ LOG_DBG_BUF((LOG_MISC, 80, header, *hash_p, hashsize));
+
+ p->flags |= PL_MARK;
+ return 0;
+}
+#endif /* USE_X509 || USE_KEYNOTE */
+
+static int
+pre_shared_encode_hash(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ size_t hashsize = ie->hash->hashsize;
+ char header[80];
+ int initiator = exchange->initiator;
+ u_int8_t *buf;
+
+ buf = ipsec_add_hash_payload(msg, hashsize);
+ if (!buf)
+ return -1;
+
+ if (ike_auth_hash(exchange, buf + ISAKMP_HASH_DATA_OFF) == -1)
+ return -1;
+
+ snprintf(header, sizeof header, "pre_shared_encode_hash: HASH_%c",
+ initiator ? 'I' : 'R');
+ LOG_DBG_BUF((LOG_MISC, 80, header, buf + ISAKMP_HASH_DATA_OFF,
+ hashsize));
+ return 0;
+}
+
+#if defined (USE_X509) || defined (USE_KEYNOTE)
+/* Encrypt the HASH into a SIG type. */
+static int
+rsa_sig_encode_hash(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ size_t hashsize = ie->hash->hashsize, id_len;
+ struct cert_handler *handler;
+ char header[80];
+ int initiator = exchange->initiator, idtype;
+ u_int8_t *buf, *data, *buf2, *id;
+ u_int32_t datalen;
+ int32_t sigsize;
+ void *sent_key;
+
+ id = initiator ? exchange->id_i : exchange->id_r;
+ id_len = initiator ? exchange->id_i_len : exchange->id_r_len;
+
+ /* We may have been provided these by the kernel */
+ buf = (u_int8_t *) conf_get_str(exchange->name, "Credentials");
+ if (buf && (idtype = conf_get_num(exchange->name, "Credential_Type",
+ -1) != -1)) {
+ exchange->sent_certtype = idtype;
+ handler = cert_get(idtype);
+ if (!handler) {
+ log_print("rsa_sig_encode_hash: cert_get (%d) failed",
+ idtype);
+ return -1;
+ }
+ exchange->sent_cert =
+ handler->cert_from_printable((char *)buf);
+ if (!exchange->sent_cert) {
+ log_print("rsa_sig_encode_hash: failed to retrieve "
+ "certificate");
+ return -1;
+ }
+ handler->cert_serialize(exchange->sent_cert, &data, &datalen);
+ if (!data) {
+ log_print("rsa_sig_encode_hash: cert serialization "
+ "failed");
+ return -1;
+ }
+ goto aftercert; /* Skip all the certificate discovery */
+ }
+ /* XXX This needs to be configurable. */
+ idtype = ISAKMP_CERTENC_KEYNOTE;
+
+ /* Find a certificate with subjectAltName = id. */
+ handler = cert_get(idtype);
+ if (!handler) {
+ idtype = ISAKMP_CERTENC_X509_SIG;
+ handler = cert_get(idtype);
+ if (!handler) {
+ log_print("rsa_sig_encode_hash: cert_get(%d) failed",
+ idtype);
+ return -1;
+ }
+ }
+ if (handler->cert_obtain(id, id_len, 0, &data, &datalen) == 0) {
+ if (idtype == ISAKMP_CERTENC_KEYNOTE) {
+ idtype = ISAKMP_CERTENC_X509_SIG;
+ handler = cert_get(idtype);
+ if (!handler) {
+ log_print("rsa_sig_encode_hash: cert_get(%d) "
+ "failed", idtype);
+ return -1;
+ }
+ if (handler->cert_obtain(id, id_len, 0, &data,
+ &datalen) == 0) {
+ LOG_DBG((LOG_MISC, 10, "rsa_sig_encode_hash: "
+ "no certificate to send"));
+ goto skipcert;
+ }
+ } else {
+ LOG_DBG((LOG_MISC, 10,
+ "rsa_sig_encode_hash: no certificate to send"));
+ goto skipcert;
+ }
+ }
+ /* Let's store the certificate we are going to use */
+ exchange->sent_certtype = idtype;
+ exchange->sent_cert = handler->cert_get(data, datalen);
+ if (!exchange->sent_cert) {
+ free(data);
+ log_print("rsa_sig_encode_hash: failed to get certificate "
+ "from wire encoding");
+ return -1;
+ }
+aftercert:
+
+ buf = realloc(data, ISAKMP_CERT_SZ + datalen);
+ if (!buf) {
+ log_error("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
+ ISAKMP_CERT_SZ + datalen);
+ free(data);
+ return -1;
+ }
+ memmove(buf + ISAKMP_CERT_SZ, buf, datalen);
+ SET_ISAKMP_CERT_ENCODING(buf, idtype);
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_CERT, buf,
+ ISAKMP_CERT_SZ + datalen, 1)) {
+ free(buf);
+ return -1;
+ }
+skipcert:
+
+ /* Again, we may have these from the kernel */
+ buf = (u_int8_t *) conf_get_str(exchange->name, "PKAuthentication");
+ if (buf) {
+ key_from_printable(ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE,
+ (char *)buf, &data, &datalen);
+ if (!data) {
+ log_print("rsa_sig_encode_hash: badly formatted RSA "
+ "private key");
+ return 0;
+ }
+ sent_key = key_internalize(ISAKMP_KEY_RSA,
+ ISAKMP_KEYTYPE_PRIVATE, data, datalen);
+ if (!sent_key) {
+ log_print("rsa_sig_encode_hash: bad RSA private key "
+ "from dynamic SA acquisition subsystem");
+ return 0;
+ }
+ } else {
+ /* Try through the regular means. */
+ switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ]) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV6_ADDR:
+ util_ntoa((char **)&buf2,
+ id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] ==
+ IPSEC_ID_IPV4_ADDR ? AF_INET : AF_INET6,
+ id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ);
+ if (!buf2)
+ return 0;
+ break;
+
+ case IPSEC_ID_FQDN:
+ case IPSEC_ID_USER_FQDN:
+ buf2 = calloc(id_len - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ + 1, sizeof(char));
+ if (!buf2) {
+ log_print("rsa_sig_encode_hash: malloc (%lu) "
+ "failed", (unsigned long)id_len -
+ ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1);
+ return 0;
+ }
+ memcpy(buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
+ break;
+
+ /* XXX Support more ID types? */
+ default:
+ buf2 = 0;
+ return 0;
+ }
+
+ sent_key = ike_auth_get_key(IKE_AUTH_RSA_SIG, exchange->name,
+ (char *)buf2, 0);
+ free(buf2);
+
+ /* Did we find a key? */
+ if (!sent_key) {
+ log_print("rsa_sig_encode_hash: "
+ "could not get private key");
+ return -1;
+ }
+ }
+
+ /* Enable RSA blinding. */
+ if (RSA_blinding_on(sent_key, NULL) != 1) {
+ log_error("rsa_sig_encode_hash: RSA_blinding_on () failed.");
+ return -1;
+ }
+ /* XXX hashsize is not necessarily prf->blocksize. */
+ buf = malloc(hashsize);
+ if (!buf) {
+ log_error("rsa_sig_encode_hash: malloc (%lu) failed",
+ (unsigned long)hashsize);
+ return -1;
+ }
+ if (ike_auth_hash(exchange, buf) == -1) {
+ free(buf);
+ return -1;
+ }
+ snprintf(header, sizeof header, "rsa_sig_encode_hash: HASH_%c",
+ initiator ? 'I' : 'R');
+ LOG_DBG_BUF((LOG_MISC, 80, header, buf, hashsize));
+
+ data = malloc(RSA_size(sent_key));
+ if (!data) {
+ log_error("rsa_sig_encode_hash: malloc (%d) failed",
+ RSA_size(sent_key));
+ return -1;
+ }
+ sigsize = RSA_private_encrypt(hashsize, buf, data, sent_key,
+ RSA_PKCS1_PADDING);
+ if (sigsize == -1) {
+ log_print("rsa_sig_encode_hash: "
+ "RSA_private_encrypt () failed");
+ if (data)
+ free(data);
+ free(buf);
+ RSA_free(sent_key);
+ return -1;
+ }
+ datalen = (u_int32_t) sigsize;
+
+ free(buf);
+
+ buf = realloc(data, ISAKMP_SIG_SZ + datalen);
+ if (!buf) {
+ log_error("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
+ ISAKMP_SIG_SZ + datalen);
+ free(data);
+ return -1;
+ }
+ memmove(buf + ISAKMP_SIG_SZ, buf, datalen);
+
+ snprintf(header, sizeof header, "rsa_sig_encode_hash: SIG_%c",
+ initiator ? 'I' : 'R');
+ LOG_DBG_BUF((LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF,
+ datalen));
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_SIG, buf,
+ ISAKMP_SIG_SZ + datalen, 1)) {
+ free(buf);
+ return -1;
+ }
+ return 0;
+}
+#endif /* USE_X509 || USE_KEYNOTE */
+
+int
+ike_auth_hash(struct exchange *exchange, u_int8_t *buf)
+{
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ struct hash *hash = ie->hash;
+ int initiator = exchange->initiator;
+ u_int8_t *id;
+ size_t id_len;
+
+ /* Choose the right fields to fill-in. */
+ id = initiator ? exchange->id_i : exchange->id_r;
+ id_len = initiator ? exchange->id_i_len : exchange->id_r_len;
+
+ /* Allocate the prf and start calculating our HASH. */
+ prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
+ if (!prf)
+ return -1;
+
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len);
+ prf->Update(prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len);
+ prf->Update(prf->prfctx, exchange->cookies +
+ (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF),
+ ISAKMP_HDR_ICOOKIE_LEN);
+ prf->Update(prf->prfctx, exchange->cookies +
+ (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF),
+ ISAKMP_HDR_ICOOKIE_LEN);
+ prf->Update(prf->prfctx, ie->sa_i_b, ie->sa_i_b_len);
+ prf->Update(prf->prfctx, id, id_len);
+ prf->Final(buf, prf->prfctx);
+ prf_free(prf);
+ return 0;
+}
+
+#if defined (USE_RAWKEY)
+static int
+get_raw_key_from_file(int type, u_int8_t *id, size_t id_len, RSA **rsa)
+{
+ char filename[FILENAME_MAX];
+ char *fstr;
+ FILE *keyfp;
+
+ if (type != IKE_AUTH_RSA_SIG) { /* XXX More types? */
+ LOG_DBG((LOG_NEGOTIATION, 20, "get_raw_key_from_file: "
+ "invalid auth type %d\n", type));
+ return -1;
+ }
+ *rsa = 0;
+
+ fstr = conf_get_str("General", "Pubkey-directory");
+ if (!fstr)
+ fstr = CONF_DFLT_PUBKEY_DIR;
+
+ if (snprintf(filename, sizeof filename, "%s/", fstr) >
+ (int)sizeof filename - 1)
+ return -1;
+
+ fstr = ipsec_id_string(id, id_len);
+ if (!fstr) {
+ LOG_DBG((LOG_NEGOTIATION, 50, "get_raw_key_from_file: "
+ "ipsec_id_string failed"));
+ return -1;
+ }
+ strlcat(filename, fstr, sizeof filename - strlen(filename));
+ free(fstr);
+
+ /* If the file does not exist, fail silently. */
+ keyfp = monitor_fopen(filename, "r");
+ if (keyfp) {
+ *rsa = PEM_read_RSA_PUBKEY(keyfp, NULL, NULL, NULL);
+ fclose(keyfp);
+ } else if (errno != ENOENT) {
+ log_error("get_raw_key_from_file: monitor_fopen "
+ "(\"%s\", \"r\") failed", filename);
+ return -1;
+ } else
+ LOG_DBG((LOG_NEGOTIATION, 50,
+ "get_raw_key_from_file: file %s not found", filename));
+
+ return (*rsa ? 0 : -1);
+}
+#endif /* USE_RAWKEY */
diff --git a/keyexchange/isakmpd-20041012/ike_auth.h b/keyexchange/isakmpd-20041012/ike_auth.h
new file mode 100644
index 0000000..39b0923
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_auth.h
@@ -0,0 +1,48 @@
+/* $OpenBSD: ike_auth.h,v 1.5 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: ike_auth.h,v 1.5 1998/08/16 19:55:24 provos Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IKE_AUTH_H_
+#define _IKE_AUTH_H_
+
+#include <sys/types.h>
+
+struct exchange;
+
+struct ike_auth {
+ u_int16_t id;
+ u_int8_t *(*gen_skeyid) (struct exchange *, size_t *);
+ int (*decode_hash) (struct message *);
+ int (*encode_hash) (struct message *);
+};
+
+extern struct ike_auth *ike_auth_get(u_int16_t);
+
+#endif /* _IKE_AUTH_H_ */
diff --git a/keyexchange/isakmpd-20041012/ike_main_mode.c b/keyexchange/isakmpd-20041012/ike_main_mode.c
new file mode 100644
index 0000000..1308564
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_main_mode.c
@@ -0,0 +1,124 @@
+/* $OpenBSD: ike_main_mode.c,v 1.15 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: ike_main_mode.c,v 1.77 1999/04/25 22:12:34 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "conf.h"
+#include "constants.h"
+#include "crypto.h"
+#include "dh.h"
+#include "doi.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "ike_main_mode.h"
+#include "ike_phase_1.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "isakmp.h"
+#include "log.h"
+#include "math_group.h"
+#include "message.h"
+#include "prf.h"
+#include "sa.h"
+#include "transport.h"
+#include "util.h"
+
+static int initiator_send_ID_AUTH(struct message *);
+static int responder_send_ID_AUTH(struct message *);
+static int responder_send_KE_NONCE(struct message *);
+
+int (*ike_main_mode_initiator[]) (struct message *) = {
+ ike_phase_1_initiator_send_SA,
+ ike_phase_1_initiator_recv_SA,
+ ike_phase_1_initiator_send_KE_NONCE,
+ ike_phase_1_initiator_recv_KE_NONCE,
+ initiator_send_ID_AUTH,
+ ike_phase_1_recv_ID_AUTH
+};
+
+int (*ike_main_mode_responder[]) (struct message *) = {
+ ike_phase_1_responder_recv_SA,
+ ike_phase_1_responder_send_SA,
+ ike_phase_1_recv_KE_NONCE,
+ responder_send_KE_NONCE,
+ ike_phase_1_recv_ID_AUTH,
+ responder_send_ID_AUTH
+};
+
+static int
+initiator_send_ID_AUTH(struct message *msg)
+{
+ msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+
+ if (ike_phase_1_send_ID(msg))
+ return -1;
+
+ if (ike_phase_1_send_AUTH(msg))
+ return -1;
+
+ return ipsec_initial_contact(msg);
+}
+
+/* Send our public DH value and a nonce to the initiator. */
+int
+responder_send_KE_NONCE(struct message *msg)
+{
+ /* XXX Should we really just use the initiator's nonce size? */
+ if (ike_phase_1_send_KE_NONCE(msg, msg->exchange->nonce_i_len))
+ return -1;
+
+ /*
+ * Calculate DH values & key material in parallel with the message
+ * going on a roundtrip over the wire.
+ */
+ message_register_post_send(msg,
+ (void (*)(struct message *))ike_phase_1_post_exchange_KE_NONCE);
+
+ return 0;
+}
+
+static int
+responder_send_ID_AUTH(struct message *msg)
+{
+ msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+
+ if (ike_phase_1_responder_send_ID_AUTH(msg))
+ return -1;
+
+ return ipsec_initial_contact(msg);
+}
diff --git a/keyexchange/isakmpd-20041012/ike_main_mode.h b/keyexchange/isakmpd-20041012/ike_main_mode.h
new file mode 100644
index 0000000..3e0d173
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_main_mode.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: ike_main_mode.h,v 1.6 2004/05/23 18:17:56 hshoexer Exp $ */
+/* $EOM: ike_main_mode.h,v 1.1 1998/07/25 11:22:07 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IKE_MAIN_MODE_H_
+#define _IKE_MAIN_MODE_H_
+
+struct message;
+
+extern int (*ike_main_mode_initiator[]) (struct message *msg);
+extern int (*ike_main_mode_responder[]) (struct message *msg);
+
+#endif /* _IKE_MAIN_MODE_H_ */
diff --git a/keyexchange/isakmpd-20041012/ike_phase_1.c b/keyexchange/isakmpd-20041012/ike_phase_1.c
new file mode 100644
index 0000000..7f72a25
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_phase_1.c
@@ -0,0 +1,1396 @@
+/* $OpenBSD: ike_phase_1.c,v 1.56 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: ike_phase_1.c,v 1.31 2000/12/11 23:47:56 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2001, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "conf.h"
+#include "constants.h"
+#include "crypto.h"
+#include "dh.h"
+#include "doi.h"
+#ifdef USE_DPD
+#include "dpd.h"
+#endif
+#include "exchange.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "ike_phase_1.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "isakmp.h"
+#include "log.h"
+#include "math_group.h"
+#include "message.h"
+#if defined (USE_NAT_TRAVERSAL)
+#include "nat_traversal.h"
+#endif
+#include "prf.h"
+#include "sa.h"
+#include "transport.h"
+#include "util.h"
+
+static int attribute_unacceptable(u_int16_t, u_int8_t *, u_int16_t,
+ void *);
+static int ike_phase_1_validate_prop(struct exchange *, struct sa *,
+ struct sa *);
+
+/* Offer a set of transforms to the responder in the MSG message. */
+int
+ike_phase_1_initiator_send_SA(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *attr;
+ u_int8_t **transform = 0;
+ size_t transforms_len = 0, proposal_len, sa_len;
+ size_t *transform_len = 0;
+ struct conf_list *conf, *life_conf;
+ struct conf_list_node *xf, *life;
+ int value, update_nextp;
+ size_t i;
+ struct payload *p;
+ struct proto *proto;
+ struct proto_attr *pa;
+ int group_desc = -1, new_group_desc;
+
+ /* Get the list of transforms. */
+ conf = conf_get_list(exchange->policy, "Transforms");
+ if (!conf)
+ return -1;
+
+ transform = calloc(conf->cnt, sizeof *transform);
+ if (!transform) {
+ log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) "
+ "failed", (u_long)conf->cnt, (u_long) sizeof *transform);
+ goto bail_out;
+ }
+ transform_len = calloc(conf->cnt, sizeof *transform_len);
+ if (!transform_len) {
+ log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) "
+ "failed", (u_long)conf->cnt,
+ (u_long) sizeof *transform_len);
+ goto bail_out;
+ }
+ for (xf = TAILQ_FIRST(&conf->fields), i = 0; i < conf->cnt;
+ i++, xf = TAILQ_NEXT(xf, link)) {
+ /* XXX The sizing needs to be dynamic. */
+ transform[i] = malloc(ISAKMP_TRANSFORM_SA_ATTRS_OFF +
+ 16 * ISAKMP_ATTR_VALUE_OFF);
+ if (!transform[i]) {
+ log_error("ike_phase_1_initiator_send_SA: malloc (%d) "
+ "failed", ISAKMP_TRANSFORM_SA_ATTRS_OFF +
+ 16 * ISAKMP_ATTR_VALUE_OFF);
+ goto bail_out;
+ }
+ SET_ISAKMP_TRANSFORM_NO(transform[i], i);
+ SET_ISAKMP_TRANSFORM_ID(transform[i], IPSEC_TRANSFORM_KEY_IKE);
+ SET_ISAKMP_TRANSFORM_RESERVED(transform[i], 0);
+
+ attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF;
+
+ if (attribute_set_constant(xf->field, "ENCRYPTION_ALGORITHM",
+ ike_encrypt_cst, IKE_ATTR_ENCRYPTION_ALGORITHM, &attr))
+ goto bail_out;
+
+ if (attribute_set_constant(xf->field, "HASH_ALGORITHM",
+ ike_hash_cst, IKE_ATTR_HASH_ALGORITHM, &attr))
+ goto bail_out;
+
+ if (attribute_set_constant(xf->field, "AUTHENTICATION_METHOD",
+ ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD, &attr))
+ goto bail_out;
+
+ if (attribute_set_constant(xf->field, "GROUP_DESCRIPTION",
+ ike_group_desc_cst, IKE_ATTR_GROUP_DESCRIPTION, &attr)) {
+ /*
+ * If no group description exists, try looking for
+ * a user-defined one.
+ */
+ if (attribute_set_constant(xf->field, "GROUP_TYPE",
+ ike_group_cst, IKE_ATTR_GROUP_TYPE, &attr))
+ goto bail_out;
+
+#if 0
+ if (attribute_set_bignum(xf->field, "GROUP_PRIME",
+ IKE_ATTR_GROUP_PRIME, &attr))
+ goto bail_out;
+
+ if (attribute_set_bignum(xf->field,
+ "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_2,
+ &attr))
+ goto bail_out;
+
+ if (attribute_set_bignum(xf->field,
+ "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_2,
+ &attr))
+ goto bail_out;
+
+ if (attribute_set_bignum(xf->field, "GROUP_CURVE_A",
+ IKE_ATTR_GROUP_CURVE_A, &attr))
+ goto bail_out;
+
+ if (attribute_set_bignum(xf->field, "GROUP_CURVE_B",
+ IKE_ATTR_GROUP_CURVE_B, &attr))
+ goto bail_out;
+#endif
+ }
+ /*
+ * Life durations are special, we should be able to specify
+ * several, one per type.
+ */
+ life_conf = conf_get_list(xf->field, "Life");
+ if (life_conf) {
+ for (life = TAILQ_FIRST(&life_conf->fields); life;
+ life = TAILQ_NEXT(life, link)) {
+ attribute_set_constant(life->field,
+ "LIFE_TYPE", ike_duration_cst,
+ IKE_ATTR_LIFE_TYPE, &attr);
+
+ /*
+ * XXX Deals with 16 and 32 bit lifetimes
+ * only
+ */
+ value = conf_get_num(life->field,
+ "LIFE_DURATION", 0);
+ if (value) {
+ if (value <= 0xffff)
+ attr = attribute_set_basic(
+ attr,
+ IKE_ATTR_LIFE_DURATION,
+ value);
+ else {
+ value = htonl(value);
+ attr = attribute_set_var(attr,
+ IKE_ATTR_LIFE_DURATION,
+ (u_int8_t *)&value,
+ sizeof value);
+ }
+ }
+ }
+ conf_free_list(life_conf);
+ }
+ attribute_set_constant(xf->field, "PRF", ike_prf_cst,
+ IKE_ATTR_PRF, &attr);
+
+ value = conf_get_num(xf->field, "KEY_LENGTH", 0);
+ if (value)
+ attr = attribute_set_basic(attr, IKE_ATTR_KEY_LENGTH,
+ value);
+
+ value = conf_get_num(xf->field, "FIELD_SIZE", 0);
+ if (value)
+ attr = attribute_set_basic(attr, IKE_ATTR_FIELD_SIZE,
+ value);
+
+ value = conf_get_num(xf->field, "GROUP_ORDER", 0);
+ if (value)
+ attr = attribute_set_basic(attr, IKE_ATTR_GROUP_ORDER,
+ value);
+
+ /* Record the real transform size. */
+ transforms_len += transform_len[i] = attr - transform[i];
+
+ /* XXX I don't like exchange-specific stuff in here. */
+ if (exchange->type == ISAKMP_EXCH_AGGRESSIVE) {
+ /*
+ * Make sure that if a group description is specified,
+ * it is specified for all transforms equally.
+ */
+ attr = (u_int8_t *) conf_get_str(xf->field,
+ "GROUP_DESCRIPTION");
+ new_group_desc =
+ attr ? constant_value(ike_group_desc_cst,
+ (char *) attr) : 0;
+ if (group_desc == -1)
+ group_desc = new_group_desc;
+ else if (group_desc != new_group_desc) {
+ log_print("ike_phase_1_initiator_send_SA: "
+ "differing group descriptions in a "
+ "proposal");
+ goto bail_out;
+ }
+ }
+ /*
+ * We need to check that we actually support our
+ * configuration.
+ */
+ if (attribute_map(transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ exchange->doi->is_attribute_incompatible, msg)) {
+ log_print("ike_phase_1_initiator_send_SA: "
+ "section [%s] has unsupported attribute(s)",
+ xf->field);
+ goto bail_out;
+ }
+ }
+
+ /* XXX I don't like exchange-specific stuff in here. */
+ if (exchange->type == ISAKMP_EXCH_AGGRESSIVE)
+ ie->group = group_get(group_desc);
+
+ proposal_len = ISAKMP_PROP_SPI_OFF;
+ proposal = malloc(proposal_len);
+ if (!proposal) {
+ log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
+ (unsigned long) proposal_len);
+ goto bail_out;
+ }
+ SET_ISAKMP_PROP_NO(proposal, 1);
+ SET_ISAKMP_PROP_PROTO(proposal, ISAKMP_PROTO_ISAKMP);
+ SET_ISAKMP_PROP_SPI_SZ(proposal, 0);
+ SET_ISAKMP_PROP_NTRANSFORMS(proposal, conf->cnt);
+
+ /* XXX I would like to see this factored out. */
+ proto = calloc(1, sizeof *proto);
+ if (!proto) {
+ log_error("ike_phase_1_initiator_send_SA: "
+ "calloc (1, %lu) failed", (unsigned long) sizeof *proto);
+ goto bail_out;
+ }
+ proto->no = 1;
+ proto->proto = ISAKMP_PROTO_ISAKMP;
+ proto->sa = TAILQ_FIRST(&exchange->sa_list);
+ proto->xf_cnt = conf->cnt;
+ TAILQ_INIT(&proto->xfs);
+ for (i = 0; i < proto->xf_cnt; i++) {
+ pa = (struct proto_attr *) calloc(1, sizeof *pa);
+ if (!pa)
+ goto bail_out;
+ pa->len = transform_len[i];
+ pa->attrs = (u_int8_t *) malloc(pa->len);
+ if (!pa->attrs) {
+ free(pa);
+ goto bail_out;
+ }
+ memcpy(pa->attrs, transform[i], pa->len);
+ TAILQ_INSERT_TAIL(&proto->xfs, pa, next);
+ }
+ TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos, proto,
+ link);
+
+ sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN;
+ sa_buf = malloc(sa_len);
+ if (!sa_buf) {
+ log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
+ (unsigned long) sa_len);
+ goto bail_out;
+ }
+ SET_ISAKMP_SA_DOI(sa_buf, IPSEC_DOI_IPSEC);
+ SET_IPSEC_SIT_SIT(sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);
+
+ /*
+ * Add the payloads. As this is a SA, we need to recompute the
+ * lengths of the payloads containing others.
+ */
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
+ goto bail_out;
+ SET_ISAKMP_GEN_LENGTH(sa_buf,
+ sa_len + proposal_len + transforms_len);
+ sa_buf = 0;
+
+ saved_nextp = msg->nextp;
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL, proposal,
+ proposal_len, 0))
+ goto bail_out;
+ SET_ISAKMP_GEN_LENGTH(proposal, proposal_len + transforms_len);
+ proposal = 0;
+
+ update_nextp = 0;
+ for (i = 0; i < conf->cnt; i++) {
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM,
+ transform[i], transform_len[i], update_nextp))
+ goto bail_out;
+ update_nextp = 1;
+ transform[i] = 0;
+ }
+ msg->nextp = saved_nextp;
+
+ /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len. */
+ ie->sa_i_b_len = sa_len + proposal_len + transforms_len -
+ ISAKMP_GEN_SZ;
+ ie->sa_i_b = malloc(ie->sa_i_b_len);
+ if (!ie->sa_i_b) {
+ log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
+ (unsigned long) ie->sa_i_b_len);
+ goto bail_out;
+ }
+ memcpy(ie->sa_i_b,
+ payload_first(msg, ISAKMP_PAYLOAD_SA)->p + ISAKMP_GEN_SZ,
+ sa_len - ISAKMP_GEN_SZ);
+ memcpy(ie->sa_i_b + sa_len - ISAKMP_GEN_SZ,
+ payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL)->p, proposal_len);
+ transforms_len = 0;
+ for (i = 0, p = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM);
+ i < conf->cnt; i++, p = TAILQ_NEXT(p, link)) {
+ memcpy(ie->sa_i_b + sa_len + proposal_len + transforms_len -
+ ISAKMP_GEN_SZ, p->p, transform_len[i]);
+ transforms_len += transform_len[i];
+ }
+
+#if defined (USE_NAT_TRAVERSAL)
+ /* Advertise NAT-T capability. */
+ if (nat_t_add_vendor_payloads(msg))
+ goto bail_out;
+#endif
+
+#if defined (USE_DPD)
+ /* Advertise DPD capability. */
+ if (dpd_add_vendor_payload(msg))
+ goto bail_out;
+#endif
+
+ conf_free_list(conf);
+ free(transform);
+ free(transform_len);
+ return 0;
+
+bail_out:
+ if (sa_buf)
+ free(sa_buf);
+ if (proposal)
+ free(proposal);
+ if (transform) {
+ for (i = 0; i < conf->cnt; i++)
+ if (transform[i])
+ free(transform[i]);
+ free(transform);
+ }
+ if (transform_len)
+ free(transform_len);
+ conf_free_list(conf);
+ return -1;
+}
+
+/* Figure out what transform the responder chose. */
+int
+ike_phase_1_initiator_recv_SA(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct sa *sa = TAILQ_FIRST(&exchange->sa_list);
+ struct ipsec_exch *ie = exchange->data;
+ struct ipsec_sa *isa = sa->data;
+ struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA);
+ struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL);
+ struct payload *xf = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM);
+
+ /*
+ * IKE requires that only one SA with only one proposal exists and
+ * since we are getting an answer on our transform offer, only one
+ * transform.
+ */
+ if (TAILQ_NEXT(sa_p, link) || TAILQ_NEXT(prop, link) ||
+ TAILQ_NEXT(xf, link)) {
+ log_print("ike_phase_1_initiator_recv_SA: "
+ "multiple SA, proposal or transform payloads in phase 1");
+ /* XXX Is there a better notification type? */
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
+ return -1;
+ }
+ /* Check that the chosen transform matches an offer. */
+ if (message_negotiate_sa(msg, ike_phase_1_validate_prop) ||
+ !TAILQ_FIRST(&sa->protos))
+ return -1;
+
+ ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos), xf->p);
+
+ /* XXX I don't like exchange-specific stuff in here. */
+ if (exchange->type != ISAKMP_EXCH_AGGRESSIVE)
+ ie->group = group_get(isa->group_desc);
+
+ /* Mark the SA as handled. */
+ sa_p->flags |= PL_MARK;
+
+ return 0;
+}
+
+/* Send our public DH value and a nonce to the responder. */
+int
+ike_phase_1_initiator_send_KE_NONCE(struct message *msg)
+{
+ struct ipsec_exch *ie = msg->exchange->data;
+
+ ie->g_x_len = dh_getlen(ie->group);
+
+ /* XXX I want a better way to specify the nonce's size. */
+ return ike_phase_1_send_KE_NONCE(msg, 16);
+}
+
+/* Accept responder's public DH value and nonce. */
+int
+ike_phase_1_initiator_recv_KE_NONCE(struct message *msg)
+{
+ if (ike_phase_1_recv_KE_NONCE(msg))
+ return -1;
+
+ return ike_phase_1_post_exchange_KE_NONCE(msg);
+}
+
+/*
+ * Accept a set of transforms offered by the initiator and chose one we can
+ * handle.
+ */
+int
+ike_phase_1_responder_recv_SA(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct sa *sa = TAILQ_FIRST(&exchange->sa_list);
+ struct ipsec_sa *isa = sa->data;
+ struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA);
+ struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL);
+ struct ipsec_exch *ie = exchange->data;
+
+ /* Mark the SA as handled. */
+ sa_p->flags |= PL_MARK;
+
+ /* IKE requires that only one SA with only one proposal exists. */
+ if (TAILQ_NEXT(sa_p, link) || TAILQ_NEXT(prop, link)) {
+ log_print("ike_phase_1_responder_recv_SA: "
+ "multiple SA or proposal payloads in phase 1");
+ /* XXX Is there a better notification type? */
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
+ return -1;
+ }
+ /* Chose a transform from the SA. */
+ if (message_negotiate_sa(msg, ike_phase_1_validate_prop) ||
+ !TAILQ_FIRST(&sa->protos))
+ return -1;
+
+ /* XXX Move into message_negotiate_sa? */
+ ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos),
+ TAILQ_FIRST(&sa->protos)->chosen->p);
+
+ ie->group = group_get(isa->group_desc);
+
+ /*
+ * Check that the mandatory attributes: encryption, hash,
+ * authentication method and Diffie-Hellman group description, has
+ * been supplied.
+ */
+ if (!exchange->crypto || !ie->hash || !ie->ike_auth || !ie->group) {
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
+ return -1;
+ }
+ /* Save the body for later hash computation. */
+ ie->sa_i_b_len = GET_ISAKMP_GEN_LENGTH(sa_p->p) - ISAKMP_GEN_SZ;
+ ie->sa_i_b = malloc(ie->sa_i_b_len);
+ if (!ie->sa_i_b) {
+ /* XXX How to notify peer? */
+ log_error("ike_phase_1_responder_recv_SA: malloc (%lu) failed",
+ (unsigned long) ie->sa_i_b_len);
+ return -1;
+ }
+ memcpy(ie->sa_i_b, sa_p->p + ISAKMP_GEN_SZ, ie->sa_i_b_len);
+ return 0;
+}
+
+/* Reply with the transform we chose. */
+int
+ike_phase_1_responder_send_SA(struct message *msg)
+{
+ /* Add the SA payload with the transform that was chosen. */
+ if (message_add_sa_payload(msg))
+ return -1;
+
+#if defined (USE_NAT_TRAVERSAL)
+ /* Advertise NAT-T capability. */
+ if (nat_t_add_vendor_payloads(msg))
+ return -1;
+#endif
+
+#if defined (USE_DPD)
+ /* Advertise DPD capability. */
+ if (dpd_add_vendor_payload(msg))
+ return -1;
+#endif
+ return 0;
+}
+
+/* Send our public DH value and a nonce to the peer. */
+int
+ike_phase_1_send_KE_NONCE(struct message *msg, size_t nonce_sz)
+{
+ /* Public DH key. */
+ if (ipsec_gen_g_x(msg)) {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+ /* Generate a nonce, and add it to the message. */
+ if (exchange_gen_nonce(msg, nonce_sz)) {
+ /* XXX Log? */
+ return -1;
+ }
+ /* Try to add certificates which are acceptable for the CERTREQs */
+ if (exchange_add_certs(msg)) {
+ /* XXX Log? */
+ return -1;
+ }
+#if defined (USE_NAT_TRAVERSAL)
+ /* If this exchange uses NAT-Traversal, add NAT-D payloads now. */
+ if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER)
+ if (nat_t_exchange_add_nat_d(msg)) {
+ /* XXX Log? */
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+/* Receive our peer's public DH value and nonce. */
+int
+ike_phase_1_recv_KE_NONCE(struct message *msg)
+{
+ /* Copy out the initiator's DH public value. */
+ if (ipsec_save_g_x(msg)) {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+ /* Copy out the initiator's nonce. */
+ if (exchange_save_nonce(msg)) {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+ /* Copy out the initiator's cert requests. */
+ if (exchange_save_certreq(msg)) {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+#if defined (USE_NAT_TRAVERSAL)
+ /* MainMode: Check for NAT-D payloads and contents. */
+ if (msg->exchange->type == ISAKMP_EXCH_ID_PROT &&
+ msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER)
+ (void)nat_t_exchange_check_nat_d(msg);
+#endif
+ return 0;
+}
+
+/*
+ * Compute DH values and key material. This is done in a post-send function
+ * as that means we can do parallel work in both the initiator and responder
+ * thus speeding up exchanges.
+ */
+int
+ike_phase_1_post_exchange_KE_NONCE(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ struct hash *hash = ie->hash;
+ enum cryptoerr err;
+
+ /* Compute Diffie-Hellman shared value. */
+ ie->g_xy = malloc(ie->g_x_len);
+ if (!ie->g_xy) {
+ /* XXX How to notify peer? */
+ log_error("ike_phase_1_post_exchange_KE_NONCE: "
+ "malloc (%lu) failed", (unsigned long) ie->g_x_len);
+ return -1;
+ }
+ if (dh_create_shared(ie->group, ie->g_xy,
+ exchange->initiator ? ie->g_xr : ie->g_xi)) {
+ log_print("ike_phase_1_post_exchange_KE_NONCE: "
+ "dh_create_shared failed");
+ return -1;
+ }
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80,
+ "ike_phase_1_post_exchange_KE_NONCE: g^xy", ie->g_xy,
+ ie->g_x_len));
+
+ /* Compute the SKEYID depending on the authentication method. */
+ ie->skeyid = ie->ike_auth->gen_skeyid(exchange, &ie->skeyid_len);
+ if (!ie->skeyid) {
+ /* XXX Log and teardown? */
+ return -1;
+ }
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80,
+ "ike_phase_1_post_exchange_KE_NONCE: SKEYID", ie->skeyid,
+ ie->skeyid_len));
+
+ /* SKEYID_d. */
+ ie->skeyid_d = malloc(ie->skeyid_len);
+ if (!ie->skeyid_d) {
+ /* XXX How to notify peer? */
+ log_error("ike_phase_1_post_exchange_KE_NONCE: "
+ "malloc (%lu) failed", (unsigned long) ie->skeyid_len);
+ return -1;
+ }
+ prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
+ if (!prf) {
+ /* XXX Log and teardown? */
+ return -1;
+ }
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len);
+ prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Update(prf->prfctx, (unsigned char *) "\0", 1);
+ prf->Final(ie->skeyid_d, prf->prfctx);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80,
+ "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d", ie->skeyid_d,
+ ie->skeyid_len));
+
+ /* SKEYID_a. */
+ ie->skeyid_a = malloc(ie->skeyid_len);
+ if (!ie->skeyid_a) {
+ log_error("ike_phase_1_post_exchange_KE_NONCE: "
+ "malloc (%lu) failed", (unsigned long) ie->skeyid_len);
+ prf_free(prf);
+ return -1;
+ }
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, ie->skeyid_d, ie->skeyid_len);
+ prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len);
+ prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Update(prf->prfctx, (unsigned char *) "\1", 1);
+ prf->Final(ie->skeyid_a, prf->prfctx);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80,
+ "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a", ie->skeyid_a,
+ ie->skeyid_len));
+
+ /* SKEYID_e. */
+ ie->skeyid_e = malloc(ie->skeyid_len);
+ if (!ie->skeyid_e) {
+ /* XXX How to notify peer? */
+ log_error("ike_phase_1_post_exchange_KE_NONCE: "
+ "malloc (%lu) failed", (unsigned long) ie->skeyid_len);
+ prf_free(prf);
+ return -1;
+ }
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, ie->skeyid_a, ie->skeyid_len);
+ prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len);
+ prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Update(prf->prfctx, (unsigned char *) "\2", 1);
+ prf->Final(ie->skeyid_e, prf->prfctx);
+ prf_free(prf);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80,
+ "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e", ie->skeyid_e,
+ ie->skeyid_len));
+
+ /* Key length determination. */
+ if (!exchange->key_length)
+ exchange->key_length = exchange->crypto->keymax;
+
+ /* Derive a longer key from skeyid_e */
+ if (ie->skeyid_len < exchange->key_length) {
+ u_int16_t len, keylen;
+ u_int8_t *key, *p;
+
+ prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid_e,
+ ie->skeyid_len);
+ if (!prf) {
+ /* XXX - notify peer */
+ return -1;
+ }
+ /* Make keylen a multiple of prf->blocksize */
+ keylen = exchange->key_length;
+ if (keylen % prf->blocksize)
+ keylen += prf->blocksize - (keylen % prf->blocksize);
+
+ key = malloc(keylen);
+ if (!key) {
+ /* XXX - Notify peer. */
+ log_error("ike_phase_1_post_exchange_KE_NONCE: "
+ "malloc (%d) failed", keylen);
+ return -1;
+ }
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, (unsigned char *) "\0", 1);
+ prf->Final(key, prf->prfctx);
+
+ for (len = prf->blocksize, p = key; len < exchange->key_length;
+ len += prf->blocksize, p += prf->blocksize) {
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, p, prf->blocksize);
+ prf->Final(p + prf->blocksize, prf->prfctx);
+ }
+ prf_free(prf);
+
+ /* Setup our keystate using the derived encryption key. */
+ exchange->keystate = crypto_init(exchange->crypto, key,
+ exchange->key_length, &err);
+
+ free(key);
+ } else
+ /* Setup our keystate using the raw skeyid_e. */
+ exchange->keystate = crypto_init(exchange->crypto,
+ ie->skeyid_e, exchange->key_length, &err);
+
+ /* Special handling for DES weak keys. */
+ if (!exchange->keystate && err == EWEAKKEY &&
+ (exchange->key_length << 1) <= ie->skeyid_len) {
+ log_print("ike_phase_1_post_exchange_KE_NONCE: "
+ "weak key, trying subseq. skeyid_e");
+ exchange->keystate = crypto_init(exchange->crypto,
+ ie->skeyid_e + exchange->key_length,
+ exchange->key_length, &err);
+ }
+ if (!exchange->keystate) {
+ log_print("ike_phase_1_post_exchange_KE_NONCE: "
+ "exchange->crypto->init () failed: %d", err);
+
+ /*
+ * XXX We really need to know if problems are of transient
+ * nature or fatal (like failed assertions etc.)
+ */
+ return -1;
+ }
+ /* Setup IV. XXX Only for CBC transforms, no? */
+ hash->Init(hash->ctx);
+ hash->Update(hash->ctx, ie->g_xi, ie->g_x_len);
+ hash->Update(hash->ctx, ie->g_xr, ie->g_x_len);
+ hash->Final(hash->digest, hash->ctx);
+ crypto_init_iv(exchange->keystate, hash->digest,
+ exchange->crypto->blocksize);
+ return 0;
+}
+
+int
+ike_phase_1_responder_send_ID_AUTH(struct message *msg)
+{
+ if (ike_phase_1_send_ID(msg))
+ return -1;
+
+ return ike_phase_1_send_AUTH(msg);
+}
+
+int
+ike_phase_1_send_ID(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ u_int8_t *buf;
+ char header[80];
+ ssize_t sz;
+ struct sockaddr *src;
+ int initiator = exchange->initiator;
+ u_int8_t **id;
+ size_t *id_len;
+ char *my_id = 0, *data;
+ u_int8_t id_type;
+
+ /* Choose the right fields to fill-in. */
+ id = initiator ? &exchange->id_i : &exchange->id_r;
+ id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len;
+
+ if (exchange->name)
+ my_id = conf_get_str(exchange->name, "ID");
+
+ if (!my_id)
+ my_id = conf_get_str("General", "Default-phase-1-ID");
+
+ msg->transport->vtbl->get_src(msg->transport, &src);
+ sz = my_id ? ipsec_id_size(my_id, &id_type) : sockaddr_addrlen(src);
+ if (sz == -1)
+ return -1;
+
+ sz += ISAKMP_ID_DATA_OFF;
+ buf = malloc(sz);
+ if (!buf) {
+ log_error("ike_phase_1_send_ID: malloc (%lu) failed",
+ (unsigned long) sz);
+ return -1;
+ }
+ SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0);
+ SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0);
+ if (my_id) {
+ SET_ISAKMP_ID_TYPE(buf, id_type);
+ switch (id_type) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV6_ADDR:
+ /* Already in network byteorder. */
+ memcpy(buf + ISAKMP_ID_DATA_OFF,
+ sockaddr_addrdata(src), sockaddr_addrlen(src));
+ break;
+
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ /* Network */
+ data = conf_get_str(my_id, "Network");
+ if (!data) {
+ log_print("ike_phase_1_send_ID: section %s "
+ "has no \"Network\" tag", my_id);
+ return -1;
+ }
+ if (text2sockaddr(data, NULL, &src)) {
+ log_error("ike_phase_1_send_ID: "
+ "text2sockaddr() failed");
+ return -1;
+ }
+ memcpy(buf + ISAKMP_ID_DATA_OFF,
+ sockaddr_addrdata(src), sockaddr_addrlen(src));
+ free(src);
+ /* Netmask */
+ data = conf_get_str(my_id, "Netmask");
+ if (!data) {
+ log_print("ike_phase_1_send_ID: section %s "
+ "has no \"Netmask\" tag", my_id);
+ return -1;
+ }
+ if (text2sockaddr(data, NULL, &src)) {
+ log_error("ike_phase_1_send_ID: "
+ "text2sockaddr() failed");
+ return -1;
+ }
+ memcpy(buf + ISAKMP_ID_DATA_OFF +
+ sockaddr_addrlen(src), sockaddr_addrdata(src),
+ sockaddr_addrlen(src));
+ free(src);
+ break;
+
+ case IPSEC_ID_FQDN:
+ case IPSEC_ID_USER_FQDN:
+ case IPSEC_ID_KEY_ID:
+ data = conf_get_str(my_id, "Name");
+ if (!data) {
+ log_print("ike_phase_1_send_ID: section %s "
+ "has no \"Name\" tag", my_id);
+ return -1;
+ }
+ memcpy(buf + ISAKMP_ID_DATA_OFF, data,
+ sz - ISAKMP_ID_DATA_OFF);
+ break;
+
+ default:
+ log_print("ike_phase_1_send_ID: "
+ "unsupported ID type %d", id_type);
+ free(buf);
+ return -1;
+ }
+ } else {
+ switch (src->sa_family) {
+ case AF_INET:
+ SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR);
+ break;
+ case AF_INET6:
+ SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR);
+ break;
+ }
+ /* Already in network byteorder. */
+ memcpy(buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src),
+ sockaddr_addrlen(src));
+ }
+
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, buf, sz, 1)) {
+ free(buf);
+ return -1;
+ }
+ *id_len = sz - ISAKMP_GEN_SZ;
+ *id = malloc(*id_len);
+ if (!*id) {
+ log_error("ike_phase_1_send_ID: malloc (%lu) failed",
+ (unsigned long) *id_len);
+ return -1;
+ }
+ memcpy(*id, buf + ISAKMP_GEN_SZ, *id_len);
+ snprintf(header, sizeof header, "ike_phase_1_send_ID: %s",
+ constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(buf)));
+ LOG_DBG_BUF((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF,
+ sz - ISAKMP_ID_DATA_OFF));
+ return 0;
+}
+
+int
+ike_phase_1_send_AUTH(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+
+ if (ie->ike_auth->encode_hash(msg)) {
+ /* XXX Log? */
+ return -1;
+ }
+ /*
+ * XXX Many people say the COMMIT flag is just junk, especially in
+ * Phase 1.
+ */
+#ifdef notyet
+ if ((exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0)
+ exchange->flags |= EXCHANGE_FLAG_I_COMMITTED;
+#endif
+
+ return 0;
+}
+
+/* Receive ID and HASH and check that the exchange has been consistent. */
+int
+ike_phase_1_recv_ID_AUTH(struct message *msg)
+{
+ if (ike_phase_1_recv_ID(msg))
+ return -1;
+
+ return ike_phase_1_recv_AUTH(msg);
+}
+
+/* Receive ID. */
+int
+ike_phase_1_recv_ID(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct payload *payload;
+ char header[80], *rs = 0, *rid = 0, *p;
+ int initiator = exchange->initiator;
+ u_int8_t **id, id_type;
+ size_t *id_len;
+ ssize_t sz;
+ struct sockaddr *sa;
+
+ payload = payload_first(msg, ISAKMP_PAYLOAD_ID);
+
+ if (exchange->name)
+ rs = conf_get_str(exchange->name, "Remote-ID");
+
+ if (rs) {
+ sz = ipsec_id_size(rs, &id_type);
+ if (sz == -1) {
+ log_print("ike_phase_1_recv_ID: could not handle "
+ "specified Remote-ID [%s]", rs);
+ return -1;
+ }
+ rid = malloc(sz);
+ if (!rid) {
+ log_error("ike_phase_1_recv_ID: malloc (%lu) failed",
+ (unsigned long) sz);
+ return -1;
+ }
+ switch (id_type) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV6_ADDR:
+ p = conf_get_str(rs, "Address");
+ if (!p) {
+ log_print("ike_phase_1_recv_ID: failed to get "
+ "Address in Remote-ID section [%s]", rs);
+ free(rid);
+ return -1;
+ }
+ if (text2sockaddr(p, 0, &sa) == -1) {
+ log_print("ike_phase_1_recv_ID: "
+ "failed to parse address %s", p);
+ free(rid);
+ return -1;
+ }
+ if ((id_type == IPSEC_ID_IPV4_ADDR &&
+ sa->sa_family != AF_INET) ||
+ (id_type == IPSEC_ID_IPV6_ADDR &&
+ sa->sa_family != AF_INET6)) {
+ log_print("ike_phase_1_recv_ID: "
+ "address %s not of expected family", p);
+ free(rid);
+ free(sa);
+ return -1;
+ }
+ memcpy(rid, sockaddr_addrdata(sa),
+ sockaddr_addrlen(sa));
+ free(sa);
+ break;
+
+ case IPSEC_ID_FQDN:
+ case IPSEC_ID_USER_FQDN:
+ case IPSEC_ID_KEY_ID:
+ p = conf_get_str(rs, "Name");
+ if (!p) {
+ log_print("ike_phase_1_recv_ID: failed to "
+ "get Name in Remote-ID section [%s]", rs);
+ free(rid);
+ return -1;
+ }
+ memcpy(rid, p, sz);
+ break;
+
+ default:
+ log_print("ike_phase_1_recv_ID: "
+ "unsupported ID type %d", id_type);
+ free(rid);
+ return -1;
+ }
+
+ /* Compare expected/desired and received remote ID */
+ if (bcmp(rid, payload->p + ISAKMP_ID_DATA_OFF, sz)) {
+ log_print("ike_phase_1_recv_ID: "
+ "received remote ID other than expected %s - %s", p, payload->p);
+ free(rid);
+ return -1;
+ }
+ free(rid);
+ }
+ /* Choose the right fields to fill in */
+ id = initiator ? &exchange->id_r : &exchange->id_i;
+ id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len;
+
+ *id_len = GET_ISAKMP_GEN_LENGTH(payload->p) - ISAKMP_GEN_SZ;
+ *id = malloc(*id_len);
+ if (!*id) {
+ log_error("ike_phase_1_recv_ID: malloc (%lu) failed",
+ (unsigned long) *id_len);
+ return -1;
+ }
+ memcpy(*id, payload->p + ISAKMP_GEN_SZ, *id_len);
+ snprintf(header, sizeof header, "ike_phase_1_recv_ID: %s",
+ constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(payload->p)));
+ LOG_DBG_BUF((LOG_NEGOTIATION, 40, header,
+ payload->p + ISAKMP_ID_DATA_OFF,
+ *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF));
+ payload->flags |= PL_MARK;
+ return 0;
+}
+
+/* Receive HASH and check that the exchange has been consistent. */
+int
+ike_phase_1_recv_AUTH(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ struct hash *hash = ie->hash;
+ char header[80];
+ size_t hashsize = hash->hashsize;
+ int initiator = exchange->initiator;
+ u_int8_t **hash_p, *id;
+ size_t id_len;
+
+ /* Choose the right fields to fill in */
+ hash_p = initiator ? &ie->hash_r : &ie->hash_i;
+ id = initiator ? exchange->id_r : exchange->id_i;
+ id_len = initiator ? exchange->id_r_len : exchange->id_i_len;
+
+ /* The decoded hash will be in ie->hash_r or ie->hash_i */
+ if (ie->ike_auth->decode_hash(msg)) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1,
+ 0);
+ return -1;
+ }
+ /* Allocate the prf and start calculating his HASH. */
+ prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
+ if (!prf) {
+ /* XXX Log? */
+ return -1;
+ }
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len);
+ prf->Update(prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len);
+ prf->Update(prf->prfctx, exchange->cookies +
+ (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF),
+ ISAKMP_HDR_ICOOKIE_LEN);
+ prf->Update(prf->prfctx, exchange->cookies +
+ (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF),
+ ISAKMP_HDR_ICOOKIE_LEN);
+ prf->Update(prf->prfctx, ie->sa_i_b, ie->sa_i_b_len);
+ prf->Update(prf->prfctx, id, id_len);
+ prf->Final(hash->digest, prf->prfctx);
+ prf_free(prf);
+ snprintf(header, sizeof header, "ike_phase_1_recv_AUTH: "
+ "computed HASH_%c", initiator ? 'R' : 'I');
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80, header, hash->digest, hashsize));
+
+ /* Check that the hash we got matches the one we computed. */
+ if (memcmp(*hash_p, hash->digest, hashsize) != 0) {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* Mark message as authenticated. */
+ msg->flags |= MSG_AUTHENTICATED;
+
+ return 0;
+}
+
+struct attr_node {
+ LIST_ENTRY(attr_node) link;
+ u_int16_t type;
+};
+
+struct validation_state {
+ struct conf_list_node *xf;
+ LIST_HEAD(attr_head, attr_node) attrs;
+ char *life;
+};
+
+/* Validate a proposal inside SA according to EXCHANGE's policy. */
+static int
+ike_phase_1_validate_prop(struct exchange *exchange, struct sa *sa,
+ struct sa *isakmp_sa)
+{
+ struct conf_list *conf, *tags;
+ struct conf_list_node *xf, *tag;
+ struct proto *proto;
+ struct validation_state vs;
+ struct attr_node *node, *next_node;
+
+ /* Get the list of transforms. */
+ conf = conf_get_list(exchange->policy, "Transforms");
+ if (!conf)
+ return 0;
+
+ for (xf = TAILQ_FIRST(&conf->fields); xf; xf = TAILQ_NEXT(xf, link)) {
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link)) {
+ /* Mark all attributes in our policy as unseen. */
+ LIST_INIT(&vs.attrs);
+ vs.xf = xf;
+ vs.life = 0;
+ if (attribute_map(proto->chosen->p +
+ ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH(proto->chosen->p) -
+ ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ attribute_unacceptable, &vs))
+ goto try_next;
+
+ /* Sweep over unseen tags in this section. */
+ tags = conf_get_tag_list(xf->field);
+ if (tags) {
+ for (tag = TAILQ_FIRST(&tags->fields); tag;
+ tag = TAILQ_NEXT(tag, link))
+ /*
+ * XXX Should we care about attributes
+ * we have, they do not provide?
+ */
+ for (node = LIST_FIRST(&vs.attrs);
+ node; node = next_node) {
+ next_node =
+ LIST_NEXT(node, link);
+ if (node->type ==
+ constant_value(ike_attr_cst,
+ tag->field)) {
+ LIST_REMOVE(node, link);
+ free(node);
+ }
+ }
+ conf_free_list(tags);
+ }
+ /* Are there leftover tags in this section? */
+ node = LIST_FIRST(&vs.attrs);
+ if (node)
+ goto try_next;
+ }
+
+ /* All protocols were OK, we succeeded. */
+ LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: "
+ "success"));
+ conf_free_list(conf);
+ if (vs.life)
+ free(vs.life);
+ return 1;
+
+try_next:
+ /* Are there leftover tags in this section? */
+ node = LIST_FIRST(&vs.attrs);
+ while (node) {
+ LIST_REMOVE(node, link);
+ free(node);
+ node = LIST_FIRST(&vs.attrs);
+ }
+ if (vs.life)
+ free(vs.life);
+ }
+
+ LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure"));
+ conf_free_list(conf);
+ return 0;
+}
+
+/*
+ * Look at the attribute of type TYPE, located at VALUE for LEN bytes forward.
+ * The VVS argument holds a validation state kept across invocations.
+ * If the attribute is unacceptable to use, return non-zero, otherwise zero.
+ */
+static int
+attribute_unacceptable(u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vvs)
+{
+ struct validation_state *vs = vvs;
+ struct conf_list *life_conf;
+ struct conf_list_node *xf = vs->xf, *life;
+ char *tag = constant_lookup(ike_attr_cst, type);
+ char *str;
+ struct constant_map *map;
+ struct attr_node *node;
+ int rv;
+
+ if (!tag) {
+ LOG_DBG((LOG_NEGOTIATION, 60, "attribute_unacceptable: "
+ "attribute type %d not known", type));
+ return 1;
+ }
+ switch (type) {
+ case IKE_ATTR_ENCRYPTION_ALGORITHM:
+ case IKE_ATTR_HASH_ALGORITHM:
+ case IKE_ATTR_AUTHENTICATION_METHOD:
+ case IKE_ATTR_GROUP_DESCRIPTION:
+ case IKE_ATTR_GROUP_TYPE:
+ case IKE_ATTR_PRF:
+ str = conf_get_str(xf->field, tag);
+ if (!str) {
+ /* This attribute does not exist in this policy. */
+ LOG_DBG((LOG_NEGOTIATION, 70,
+ "attribute_unacceptable: attr %s does not exist "
+ "in %s", tag, xf->field));
+ return 1;
+ }
+ map = constant_link_lookup(ike_attr_cst, type);
+ if (!map)
+ return 1;
+
+ if ((constant_value(map, str) == decode_16(value)) ||
+ (!strcmp(str, "ANY"))) {
+ /* Mark this attribute as seen. */
+ node = malloc(sizeof *node);
+ if (!node) {
+ log_error("attribute_unacceptable: "
+ "malloc (%lu) failed",
+ (unsigned long) sizeof *node);
+ return 1;
+ }
+ node->type = type;
+ LIST_INSERT_HEAD(&vs->attrs, node, link);
+ return 0;
+ }
+ LOG_DBG((LOG_NEGOTIATION, 70,
+ "attribute_unacceptable: %s: got %s, expected %s", tag,
+ constant_name(map, decode_16(value)), str));
+ return 1;
+
+ case IKE_ATTR_GROUP_PRIME:
+ case IKE_ATTR_GROUP_GENERATOR_1:
+ case IKE_ATTR_GROUP_GENERATOR_2:
+ case IKE_ATTR_GROUP_CURVE_A:
+ case IKE_ATTR_GROUP_CURVE_B:
+ /* XXX Bignums not handled yet. */
+ return 1;
+
+ case IKE_ATTR_LIFE_TYPE:
+ case IKE_ATTR_LIFE_DURATION:
+ life_conf = conf_get_list(xf->field, "Life");
+ if (life_conf &&
+ !strcmp(conf_get_str(xf->field, "Life"), "ANY"))
+ return 0;
+
+ rv = 1;
+ if (!life_conf) {
+ /* Life attributes given, but not in our policy. */
+ LOG_DBG((LOG_NEGOTIATION, 70,
+ "attribute_unacceptable: received unexpected life "
+ "attribute"));
+ return 1;
+ }
+ /*
+ * Each lifetime type must match, otherwise we turn the
+ * proposal down. In order to do this we need to find the
+ * specific section of our policy's "Life" list and match
+ * its duration.
+ */
+ switch (type) {
+ case IKE_ATTR_LIFE_TYPE:
+ for (life = TAILQ_FIRST(&life_conf->fields); life;
+ life = TAILQ_NEXT(life, link)) {
+ str = conf_get_str(life->field, "LIFE_TYPE");
+ if (!str) {
+ LOG_DBG((LOG_NEGOTIATION, 70,
+ "attribute_unacceptable: "
+ "section [%s] has no LIFE_TYPE",
+ life->field));
+ continue;
+ }
+
+ /*
+ * If this is the type we are looking at,
+ * to save a pointer this section in vs->life.
+ */
+ if (constant_value(ike_duration_cst, str) ==
+ decode_16(value)) {
+ vs->life = strdup(life->field);
+ rv = 0;
+ goto bail_out;
+ }
+ }
+ LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable:"
+ " unrecognized LIFE_TYPE %d", decode_16(value)));
+ vs->life = 0;
+ break;
+
+ case IKE_ATTR_LIFE_DURATION:
+ if (!vs->life) {
+ LOG_DBG((LOG_NEGOTIATION, 70,
+ "attribute_unacceptable: "
+ "LIFE_DURATION without LIFE_TYPE"));
+ rv = 1;
+ goto bail_out;
+ }
+ str = conf_get_str(vs->life, "LIFE_DURATION");
+ if (str) {
+ if (!strcmp(str, "ANY"))
+ rv = 0;
+ else
+ rv = !conf_match_num(vs->life,
+ "LIFE_DURATION",
+ len == 4 ? decode_32(value) :
+ decode_16(value));
+ } else {
+ LOG_DBG((LOG_NEGOTIATION, 70,
+ "attribute_unacceptable: section [%s] has "
+ "no LIFE_DURATION", vs->life));
+ rv = 1;
+ }
+
+ free(vs->life);
+ vs->life = 0;
+ break;
+ }
+
+bail_out:
+ conf_free_list(life_conf);
+ return rv;
+
+ case IKE_ATTR_KEY_LENGTH:
+ case IKE_ATTR_FIELD_SIZE:
+ case IKE_ATTR_GROUP_ORDER:
+ if (conf_match_num(xf->field, tag, decode_16(value))) {
+ /* Mark this attribute as seen. */
+ node = malloc(sizeof *node);
+ if (!node) {
+ log_error("attribute_unacceptable: "
+ "malloc (%lu) failed",
+ (unsigned long) sizeof *node);
+ return 1;
+ }
+ node->type = type;
+ LIST_INSERT_HEAD(&vs->attrs, node, link);
+ return 0;
+ }
+ return 1;
+ }
+ return 1;
+}
diff --git a/keyexchange/isakmpd-20041012/ike_phase_1.h b/keyexchange/isakmpd-20041012/ike_phase_1.h
new file mode 100644
index 0000000..1252664
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_phase_1.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: ike_phase_1.h,v 1.4 2004/04/15 18:39:25 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IKE_PHASE_1_H_
+#define _IKE_PHASE_1_H_
+
+struct message;
+
+extern int ike_phase_1_initiator_recv_KE_NONCE(struct message *);
+extern int ike_phase_1_initiator_recv_SA(struct message *);
+extern int ike_phase_1_initiator_send_KE_NONCE(struct message *);
+extern int ike_phase_1_initiator_send_SA(struct message *);
+extern int ike_phase_1_post_exchange_KE_NONCE(struct message *);
+extern int ike_phase_1_recv_AUTH(struct message *);
+extern int ike_phase_1_recv_ID(struct message *);
+extern int ike_phase_1_recv_ID_AUTH(struct message *);
+extern int ike_phase_1_recv_KE_NONCE(struct message *);
+extern int ike_phase_1_responder_recv_SA(struct message *);
+extern int ike_phase_1_responder_send_SA(struct message *);
+extern int ike_phase_1_responder_send_ID_AUTH(struct message *);
+extern int ike_phase_1_send_AUTH(struct message *);
+extern int ike_phase_1_send_ID(struct message *);
+extern int ike_phase_1_send_ID_AUTH(struct message *);
+extern int ike_phase_1_send_KE_NONCE(struct message *, size_t);
+
+#endif /* _IKE_PHASE_1_H_ */
diff --git a/keyexchange/isakmpd-20041012/ike_quick_mode.c b/keyexchange/isakmpd-20041012/ike_quick_mode.c
new file mode 100644
index 0000000..75bec87
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_quick_mode.c
@@ -0,0 +1,1989 @@
+/* $OpenBSD: ike_quick_mode.c,v 1.87 2004/09/17 13:53:08 ho Exp $ */
+/* $EOM: ike_quick_mode.c,v 1.139 2001/01/26 10:43:17 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined (USE_POLICY) || defined (USE_KEYNOTE)
+#include <sys/types.h>
+#include <regex.h>
+#include <keynote.h>
+#endif
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "conf.h"
+#include "connection.h"
+#include "dh.h"
+#include "doi.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ike_quick_mode.h"
+#include "ipsec.h"
+#include "log.h"
+#include "math_group.h"
+#include "message.h"
+#include "policy.h"
+#include "prf.h"
+#include "sa.h"
+#include "transport.h"
+#include "util.h"
+#include "key.h"
+
+#ifdef USE_X509
+#include "x509.h"
+#endif
+
+static void gen_g_xy(struct message *);
+static int initiator_send_HASH_SA_NONCE(struct message *);
+static int initiator_recv_HASH_SA_NONCE(struct message *);
+static int initiator_send_HASH(struct message *);
+static void post_quick_mode(struct message *);
+static int responder_recv_HASH_SA_NONCE(struct message *);
+static int responder_send_HASH_SA_NONCE(struct message *);
+static int responder_recv_HASH(struct message *);
+
+#ifdef USE_POLICY
+static int check_policy(struct exchange *, struct sa *, struct sa *);
+#endif
+
+int (*ike_quick_mode_initiator[])(struct message *) = {
+ initiator_send_HASH_SA_NONCE,
+ initiator_recv_HASH_SA_NONCE,
+ initiator_send_HASH
+};
+
+int (*ike_quick_mode_responder[])(struct message *) = {
+ responder_recv_HASH_SA_NONCE,
+ responder_send_HASH_SA_NONCE,
+ responder_recv_HASH
+};
+
+#ifdef USE_POLICY
+
+/* How many return values will policy handle -- true/false for now */
+#define RETVALUES_NUM 2
+
+/*
+ * Given an exchange and our policy, check whether the SA and IDs are
+ * acceptable.
+ */
+static int
+check_policy(struct exchange *exchange, struct sa *sa, struct sa *isakmp_sa)
+{
+ char *return_values[RETVALUES_NUM];
+ char **principal = 0;
+ int i, len, result = 0, nprinc = 0;
+ int *x509_ids = 0, *keynote_ids = 0;
+ unsigned char hashbuf[20]; /* Set to the largest digest result */
+#ifdef USE_X509
+ struct keynote_deckey dc;
+ X509_NAME *subject;
+#endif
+
+ /* Do we want to use keynote policies? */
+ if (ignore_policy ||
+ strncmp("yes", conf_get_str("General", "Use-Keynote"), 3))
+ return 1;
+
+ /* Initialize if necessary -- e.g., if pre-shared key auth was used */
+ if (isakmp_sa->policy_id < 0) {
+ if ((isakmp_sa->policy_id = kn_init()) == -1) {
+ log_print("check_policy: "
+ "failed to initialize policy session");
+ return 0;
+ }
+ }
+ /* Add the callback that will handle attributes. */
+ if (kn_add_action(isakmp_sa->policy_id, ".*", (char *)policy_callback,
+ ENVIRONMENT_FLAG_FUNC | ENVIRONMENT_FLAG_REGEX) == -1) {
+ log_print("check_policy: "
+ "kn_add_action (%d, \".*\", %p, FUNC | REGEX) failed",
+ isakmp_sa->policy_id, policy_callback);
+ kn_close(isakmp_sa->policy_id);
+ isakmp_sa->policy_id = -1;
+ return 0;
+ }
+ if (policy_asserts_num) {
+ keynote_ids = calloc(policy_asserts_num, sizeof *keynote_ids);
+ if (!keynote_ids) {
+ log_error("check_policy: calloc (%d, %lu) failed",
+ policy_asserts_num,
+ (unsigned long)sizeof *keynote_ids);
+ return 0;
+ }
+ }
+ /* Add the policy assertions */
+ for (i = 0; i < policy_asserts_num; i++)
+ keynote_ids[i] = kn_add_assertion(isakmp_sa->policy_id,
+ policy_asserts[i],
+ strlen(policy_asserts[i]), ASSERT_FLAG_LOCAL);
+
+ /* Initialize -- we'll let the callback do all the work. */
+ policy_exchange = exchange;
+ policy_sa = sa;
+ policy_isakmp_sa = isakmp_sa;
+
+ /* Set the return values; true/false for now at least. */
+ return_values[0] = "false"; /* Order of values in array is
+ * important. */
+ return_values[1] = "true";
+
+ /* Create a principal (authorizer) for the SA/ID request. */
+ switch (isakmp_sa->recv_certtype) {
+ case ISAKMP_CERTENC_NONE:
+ /*
+ * For shared keys, just duplicate the passphrase with the
+ * appropriate prefix tag.
+ */
+ nprinc = 3;
+ principal = calloc(nprinc, sizeof *principal);
+ if (!principal) {
+ log_error("check_policy: calloc (%d, %lu) failed",
+ nprinc, (unsigned long)sizeof *principal);
+ goto policydone;
+ }
+ len = strlen(isakmp_sa->recv_key) + sizeof "passphrase:";
+ principal[0] = calloc(len, sizeof(char));
+ if (!principal[0]) {
+ log_error("check_policy: calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto policydone;
+ }
+ /*
+ * XXX Consider changing the magic hash lengths with
+ * constants.
+ */
+ strlcpy(principal[0], "passphrase:", len);
+ memcpy(principal[0] + sizeof "passphrase:" - 1,
+ isakmp_sa->recv_key, strlen(isakmp_sa->recv_key));
+
+ len = sizeof "passphrase-md5-hex:" + 2 * 16;
+ principal[1] = calloc(len, sizeof(char));
+ if (!principal[1]) {
+ log_error("check_policy: calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto policydone;
+ }
+ strlcpy(principal[1], "passphrase-md5-hex:", len);
+ MD5(isakmp_sa->recv_key, strlen(isakmp_sa->recv_key), hashbuf);
+ for (i = 0; i < 16; i++)
+ snprintf(principal[1] + 2 * i +
+ sizeof "passphrase-md5-hex:" - 1, 3, "%02x",
+ hashbuf[i]);
+
+ len = sizeof "passphrase-sha1-hex:" + 2 * 20;
+ principal[2] = calloc(len, sizeof(char));
+ if (!principal[2]) {
+ log_error("check_policy: calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto policydone;
+ }
+ strlcpy(principal[2], "passphrase-sha1-hex:", len);
+ SHA1(isakmp_sa->recv_key, strlen(isakmp_sa->recv_key),
+ hashbuf);
+ for (i = 0; i < 20; i++)
+ snprintf(principal[2] + 2 * i +
+ sizeof "passphrase-sha1-hex:" - 1, 3, "%02x",
+ hashbuf[i]);
+ break;
+
+ case ISAKMP_CERTENC_KEYNOTE:
+#ifdef USE_KEYNOTE
+ nprinc = 1;
+
+ principal = calloc(nprinc, sizeof *principal);
+ if (!principal) {
+ log_error("check_policy: calloc (%d, %lu) failed",
+ nprinc, (unsigned long)sizeof *principal);
+ goto policydone;
+ }
+ /* Dup the keys */
+ principal[0] = strdup(isakmp_sa->keynote_key);
+ if (!principal[0]) {
+ log_error("check_policy: calloc (%lu, %lu) failed",
+ (unsigned long)strlen(isakmp_sa->keynote_key),
+ (unsigned long)sizeof(char));
+ goto policydone;
+ }
+#endif
+ break;
+
+ case ISAKMP_CERTENC_X509_SIG:
+#ifdef USE_X509
+ principal = calloc(2, sizeof *principal);
+ if (!principal) {
+ log_error("check_policy: calloc (2, %lu) failed",
+ (unsigned long)sizeof *principal);
+ goto policydone;
+ }
+ if (isakmp_sa->recv_keytype == ISAKMP_KEY_RSA)
+ dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
+ else {
+ log_error("check_policy: "
+ "unknown/unsupported public key algorithm %d",
+ isakmp_sa->recv_keytype);
+ goto policydone;
+ }
+
+ dc.dec_key = isakmp_sa->recv_key;
+ principal[0] = kn_encode_key(&dc, INTERNAL_ENC_PKCS1,
+ ENCODING_HEX, KEYNOTE_PUBLIC_KEY);
+ if (keynote_errno == ERROR_MEMORY) {
+ log_print("check_policy: "
+ "failed to get memory for public key");
+ goto policydone;
+ }
+ if (!principal[0]) {
+ log_print("check_policy: "
+ "failed to allocate memory for principal");
+ goto policydone;
+ }
+ len = strlen(principal[0]) + sizeof "rsa-hex:";
+ principal[1] = calloc(len, sizeof(char));
+ if (!principal[1]) {
+ log_error("check_policy: calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto policydone;
+ }
+ snprintf(principal[1], len, "rsa-hex:%s", principal[0]);
+ free(principal[0]);
+ principal[0] = principal[1];
+ principal[1] = 0;
+
+ /* Generate a "DN:" principal. */
+ subject = X509_get_subject_name(isakmp_sa->recv_cert);
+ if (subject) {
+ principal[1] = calloc(259, sizeof(char));
+ if (!principal[1]) {
+ log_error("check_policy: "
+ "calloc (259, %lu) failed",
+ (unsigned long)sizeof(char));
+ goto policydone;
+ }
+ strlcpy(principal[1], "DN:", 259);
+ X509_NAME_oneline(subject, principal[1] + 3, 256);
+ nprinc = 2;
+ } else {
+ nprinc = 1;
+ }
+ break;
+#endif
+
+ /* XXX Eventually handle these. */
+ case ISAKMP_CERTENC_PKCS:
+ case ISAKMP_CERTENC_PGP:
+ case ISAKMP_CERTENC_DNS:
+ case ISAKMP_CERTENC_X509_KE:
+ case ISAKMP_CERTENC_KERBEROS:
+ case ISAKMP_CERTENC_CRL:
+ case ISAKMP_CERTENC_ARL:
+ case ISAKMP_CERTENC_SPKI:
+ case ISAKMP_CERTENC_X509_ATTR:
+ default:
+ log_print("check_policy: "
+ "unknown/unsupported certificate/authentication method %d",
+ isakmp_sa->recv_certtype);
+ goto policydone;
+ }
+
+ /*
+ * Add the authorizer (who is requesting the SA/ID);
+ * this may be a public or a secret key, depending on
+ * what mode of authentication we used in Phase 1.
+ */
+ for (i = 0; i < nprinc; i++) {
+ LOG_DBG((LOG_POLICY, 40, "check_policy: "
+ "adding authorizer [%s]", principal[i]));
+
+ if (kn_add_authorizer(isakmp_sa->policy_id, principal[i])
+ == -1) {
+ int j;
+
+ for (j = 0; j < i; j++)
+ kn_remove_authorizer(isakmp_sa->policy_id,
+ principal[j]);
+ log_print("check_policy: kn_add_authorizer failed");
+ goto policydone;
+ }
+ }
+
+ /* Ask policy */
+ result = kn_do_query(isakmp_sa->policy_id, return_values,
+ RETVALUES_NUM);
+ LOG_DBG((LOG_POLICY, 40, "check_policy: kn_do_query returned %d",
+ result));
+
+ /* Cleanup environment */
+ kn_cleanup_action_environment(isakmp_sa->policy_id);
+
+ /* Remove authorizers from the session */
+ for (i = 0; i < nprinc; i++) {
+ kn_remove_authorizer(isakmp_sa->policy_id, principal[i]);
+ free(principal[i]);
+ }
+
+ free(principal);
+ principal = 0;
+ nprinc = 0;
+
+ /* Check what policy said. */
+ if (result < 0) {
+ LOG_DBG((LOG_POLICY, 40, "check_policy: proposal refused"));
+ result = 0;
+ goto policydone;
+ }
+policydone:
+ for (i = 0; i < nprinc; i++)
+ if (principal && principal[i])
+ free(principal[i]);
+
+ if (principal)
+ free(principal);
+
+ /* Remove the policies */
+ for (i = 0; i < policy_asserts_num; i++) {
+ if (keynote_ids[i] != -1)
+ kn_remove_assertion(isakmp_sa->policy_id,
+ keynote_ids[i]);
+ }
+
+ if (keynote_ids)
+ free(keynote_ids);
+
+ if (x509_ids)
+ free(x509_ids);
+
+ /*
+ * XXX Currently, check_policy() is only called from
+ * message_negotiate_sa(), and so this log message reflects this.
+ * Change to something better?
+ */
+ if (result == 0)
+ log_print("check_policy: negotiated SA failed policy check");
+
+ /*
+ * Given that we have only 2 return values from policy (true/false)
+ * we can just return the query result directly (no pre-processing
+ * needed).
+ */
+ return result;
+}
+#endif /* USE_POLICY */
+
+/*
+ * Offer several sets of transforms to the responder.
+ * XXX Split this huge function up and look for common code with main mode.
+ */
+static int
+initiator_send_HASH_SA_NONCE(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct doi *doi = exchange->doi;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t ***transform = 0, ***new_transform;
+ u_int8_t **proposal = 0, **new_proposal;
+ u_int8_t *sa_buf = 0, *attr, *saved_nextp_sa, *saved_nextp_prop,
+ *id, *spi;
+ size_t spi_sz, sz;
+ size_t proposal_len = 0, proposals_len = 0, sa_len;
+ size_t **transform_len = 0, **new_transform_len;
+ size_t *transforms_len = 0, *new_transforms_len;
+ u_int32_t *transform_cnt = 0, *new_transform_cnt;
+ u_int32_t suite_no, prop_no, prot_no, xf_no, prop_cnt = 0;
+ u_int32_t i;
+ int value, update_nextp, protocol_num, proto_id;
+ struct proto *proto;
+ struct conf_list *suite_conf, *prot_conf = 0, *xf_conf = 0, *life_conf;
+ struct conf_list_node *suite, *prot, *xf, *life;
+ struct constant_map *id_map;
+ char *protocol_id, *transform_id;
+ char *local_id, *remote_id;
+ int group_desc = -1, new_group_desc;
+ struct ipsec_sa *isa = msg->isakmp_sa->data;
+ struct hash *hash = hash_get(isa->hash);
+ struct sockaddr *src;
+ struct proto_attr *pa;
+
+ if (!ipsec_add_hash_payload(msg, hash->hashsize))
+ return -1;
+
+ /* Get the list of protocol suites. */
+ suite_conf = conf_get_list(exchange->policy, "Suites");
+ if (!suite_conf)
+ return -1;
+
+ for (suite = TAILQ_FIRST(&suite_conf->fields), suite_no = prop_no = 0;
+ suite_no < suite_conf->cnt;
+ suite_no++, suite = TAILQ_NEXT(suite, link)) {
+ /* Now get each protocol in this specific protocol suite. */
+ prot_conf = conf_get_list(suite->field, "Protocols");
+ if (!prot_conf)
+ goto bail_out;
+
+ for (prot = TAILQ_FIRST(&prot_conf->fields), prot_no = 0;
+ prot_no < prot_conf->cnt;
+ prot_no++, prot = TAILQ_NEXT(prot, link)) {
+ /* Make sure we have a proposal/transform vectors. */
+ if (prop_no >= prop_cnt) {
+ /*
+ * This resize algorithm is completely
+ * arbitrary.
+ */
+ prop_cnt = 2 * prop_cnt + 10;
+ new_proposal = realloc(proposal,
+ prop_cnt * sizeof *proposal);
+ if (!new_proposal) {
+ log_error(
+ "initiator_send_HASH_SA_NONCE: "
+ "realloc (%p, %lu) failed",
+ proposal,
+ prop_cnt * (unsigned long)sizeof *proposal);
+ goto bail_out;
+ }
+ proposal = new_proposal;
+
+ new_transforms_len = realloc(transforms_len,
+ prop_cnt * sizeof *transforms_len);
+ if (!new_transforms_len) {
+ log_error(
+ "initiator_send_HASH_SA_NONCE: "
+ "realloc (%p, %lu) failed",
+ transforms_len,
+ prop_cnt * (unsigned long)sizeof *transforms_len);
+ goto bail_out;
+ }
+ transforms_len = new_transforms_len;
+
+ new_transform = realloc(transform,
+ prop_cnt * sizeof *transform);
+ if (!new_transform) {
+ log_error(
+ "initiator_send_HASH_SA_NONCE: "
+ "realloc (%p, %lu) failed",
+ transform,
+ prop_cnt * (unsigned long)sizeof *transform);
+ goto bail_out;
+ }
+ transform = new_transform;
+
+ new_transform_cnt = realloc(transform_cnt,
+ prop_cnt * sizeof *transform_cnt);
+ if (!new_transform_cnt) {
+ log_error(
+ "initiator_send_HASH_SA_NONCE: "
+ "realloc (%p, %lu) failed",
+ transform_cnt,
+ prop_cnt * (unsigned long)sizeof *transform_cnt);
+ goto bail_out;
+ }
+ transform_cnt = new_transform_cnt;
+
+ new_transform_len = realloc(transform_len,
+ prop_cnt * sizeof *transform_len);
+ if (!new_transform_len) {
+ log_error(
+ "initiator_send_HASH_SA_NONCE: "
+ "realloc (%p, %lu) failed",
+ transform_len,
+ prop_cnt * (unsigned long)sizeof *transform_len);
+ goto bail_out;
+ }
+ transform_len = new_transform_len;
+ }
+ protocol_id = conf_get_str(prot->field, "PROTOCOL_ID");
+ if (!protocol_id)
+ goto bail_out;
+
+ proto_id = constant_value(ipsec_proto_cst,
+ protocol_id);
+ switch (proto_id) {
+ case IPSEC_PROTO_IPSEC_AH:
+ id_map = ipsec_ah_cst;
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ id_map = ipsec_esp_cst;
+ break;
+
+ case IPSEC_PROTO_IPCOMP:
+ id_map = ipsec_ipcomp_cst;
+ break;
+
+ default:
+ {
+ log_print("initiator_send_HASH_SA_NONCE: "
+ "invalid PROTCOL_ID: %s", protocol_id);
+ goto bail_out;
+ }
+ }
+
+ /* Now get each transform we offer for this protocol.*/
+ xf_conf = conf_get_list(prot->field, "Transforms");
+ if (!xf_conf)
+ goto bail_out;
+ transform_cnt[prop_no] = xf_conf->cnt;
+
+ transform[prop_no] = calloc(transform_cnt[prop_no],
+ sizeof **transform);
+ if (!transform[prop_no]) {
+ log_error("initiator_send_HASH_SA_NONCE: "
+ "calloc (%d, %lu) failed",
+ transform_cnt[prop_no],
+ (unsigned long)sizeof **transform);
+ goto bail_out;
+ }
+ transform_len[prop_no] = calloc(transform_cnt[prop_no],
+ sizeof **transform_len);
+ if (!transform_len[prop_no]) {
+ log_error("initiator_send_HASH_SA_NONCE: "
+ "calloc (%d, %lu) failed",
+ transform_cnt[prop_no],
+ (unsigned long)sizeof **transform_len);
+ goto bail_out;
+ }
+ transforms_len[prop_no] = 0;
+ for (xf = TAILQ_FIRST(&xf_conf->fields), xf_no = 0;
+ xf_no < transform_cnt[prop_no];
+ xf_no++, xf = TAILQ_NEXT(xf, link)) {
+
+ /* XXX The sizing needs to be dynamic. */
+ transform[prop_no][xf_no] =
+ calloc(ISAKMP_TRANSFORM_SA_ATTRS_OFF +
+ 9 * ISAKMP_ATTR_VALUE_OFF, 1);
+ if (!transform[prop_no][xf_no]) {
+ log_error(
+ "initiator_send_HASH_SA_NONCE: "
+ "calloc (%d, 1) failed",
+ ISAKMP_TRANSFORM_SA_ATTRS_OFF +
+ 9 * ISAKMP_ATTR_VALUE_OFF);
+ goto bail_out;
+ }
+ SET_ISAKMP_TRANSFORM_NO(transform[prop_no][xf_no],
+ xf_no + 1);
+
+ transform_id = conf_get_str(xf->field,
+ "TRANSFORM_ID");
+ if (!transform_id)
+ goto bail_out;
+ SET_ISAKMP_TRANSFORM_ID(transform[prop_no][xf_no],
+ constant_value(id_map, transform_id));
+ SET_ISAKMP_TRANSFORM_RESERVED(transform[prop_no][xf_no], 0);
+
+ attr = transform[prop_no][xf_no] +
+ ISAKMP_TRANSFORM_SA_ATTRS_OFF;
+
+ /*
+ * Life durations are special, we should be
+ * able to specify several, one per type.
+ */
+ life_conf = conf_get_list(xf->field, "Life");
+ if (life_conf) {
+ for (life = TAILQ_FIRST(&life_conf->fields);
+ life;
+ life = TAILQ_NEXT(life, link)) {
+ attribute_set_constant(
+ life->field, "LIFE_TYPE",
+ ipsec_duration_cst,
+ IPSEC_ATTR_SA_LIFE_TYPE,
+ &attr);
+
+ /*
+ * XXX Deals with 16 and 32
+ * bit lifetimes only
+ */
+ value =
+ conf_get_num(life->field,
+ "LIFE_DURATION", 0);
+ if (value) {
+ if (value <= 0xffff)
+ attr =
+ attribute_set_basic(
+ attr,
+ IPSEC_ATTR_SA_LIFE_DURATION,
+ value);
+ else {
+ value = htonl(value);
+ attr =
+ attribute_set_var(
+ attr,
+ IPSEC_ATTR_SA_LIFE_DURATION,
+ (u_int8_t *)&value,
+ sizeof value);
+ }
+ }
+ }
+ conf_free_list(life_conf);
+ }
+ attribute_set_constant(xf->field,
+ "ENCAPSULATION_MODE", ipsec_encap_cst,
+ IPSEC_ATTR_ENCAPSULATION_MODE, &attr);
+
+ if (proto_id != IPSEC_PROTO_IPCOMP) {
+ attribute_set_constant(xf->field,
+ "AUTHENTICATION_ALGORITHM",
+ ipsec_auth_cst,
+ IPSEC_ATTR_AUTHENTICATION_ALGORITHM,
+ &attr);
+
+ attribute_set_constant(xf->field,
+ "GROUP_DESCRIPTION",
+ ike_group_desc_cst,
+ IPSEC_ATTR_GROUP_DESCRIPTION, &attr);
+
+ value = conf_get_num(xf->field,
+ "KEY_LENGTH", 0);
+ if (value)
+ attr = attribute_set_basic(
+ attr,
+ IPSEC_ATTR_KEY_LENGTH,
+ value);
+
+ value = conf_get_num(xf->field,
+ "KEY_ROUNDS", 0);
+ if (value)
+ attr = attribute_set_basic(
+ attr,
+ IPSEC_ATTR_KEY_ROUNDS,
+ value);
+ } else {
+ value = conf_get_num(xf->field,
+ "COMPRESS_DICTIONARY_SIZE", 0);
+ if (value)
+ attr = attribute_set_basic(
+ attr,
+ IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE,
+ value);
+
+ value = conf_get_num(xf->field,
+ "COMPRESS_PRIVATE_ALGORITHM", 0);
+ if (value)
+ attr = attribute_set_basic(
+ attr,
+ IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM,
+ value);
+ }
+
+ value = conf_get_num(xf->field, "ECN_TUNNEL",
+ 0);
+ if (value)
+ attr = attribute_set_basic(attr,
+ IPSEC_ATTR_ECN_TUNNEL, value);
+
+ /* Record the real transform size. */
+ transforms_len[prop_no] +=
+ (transform_len[prop_no][xf_no]
+ = attr - transform[prop_no][xf_no]);
+
+ if (proto_id != IPSEC_PROTO_IPCOMP) {
+ /*
+ * Make sure that if a group
+ * description is specified, it is
+ * specified for all transforms
+ * equally.
+ */
+ attr =
+ (u_int8_t *)conf_get_str(xf->field,
+ "GROUP_DESCRIPTION");
+ new_group_desc
+ = attr ? constant_value(ike_group_desc_cst,
+ (char *)attr) : 0;
+ if (group_desc == -1)
+ group_desc = new_group_desc;
+ else if (group_desc != new_group_desc) {
+ log_print("initiator_send_HASH_SA_NONCE: "
+ "differing group descriptions in a proposal");
+ goto bail_out;
+ }
+ }
+ }
+ conf_free_list(xf_conf);
+ xf_conf = 0;
+
+ /*
+ * Get SPI from application.
+ * XXX Should we care about unknown constants?
+ */
+ protocol_num = constant_value(ipsec_proto_cst,
+ protocol_id);
+ spi = doi->get_spi(&spi_sz, protocol_num, msg);
+ if (spi_sz && !spi) {
+ log_print("initiator_send_HASH_SA_NONCE: "
+ "doi->get_spi failed");
+ goto bail_out;
+ }
+ proposal_len = ISAKMP_PROP_SPI_OFF + spi_sz;
+ proposals_len +=
+ proposal_len + transforms_len[prop_no];
+ proposal[prop_no] = malloc(proposal_len);
+ if (!proposal[prop_no]) {
+ log_error("initiator_send_HASH_SA_NONCE: "
+ "malloc (%lu) failed",
+ (unsigned long)proposal_len);
+ goto bail_out;
+ }
+ SET_ISAKMP_PROP_NO(proposal[prop_no], suite_no + 1);
+ SET_ISAKMP_PROP_PROTO(proposal[prop_no], protocol_num);
+
+ /* XXX I would like to see this factored out. */
+ proto = calloc(1, sizeof *proto);
+ if (!proto) {
+ log_error("initiator_send_HASH_SA_NONCE: "
+ "calloc (1, %lu) failed",
+ (unsigned long)sizeof *proto);
+ goto bail_out;
+ }
+ if (doi->proto_size) {
+ proto->data = calloc(1, doi->proto_size);
+ if (!proto->data) {
+ log_error(
+ "initiator_send_HASH_SA_NONCE: "
+ "calloc (1, %lu) failed",
+ (unsigned long)doi->proto_size);
+ goto bail_out;
+ }
+ }
+ proto->no = suite_no + 1;
+ proto->proto = protocol_num;
+ proto->sa = TAILQ_FIRST(&exchange->sa_list);
+ proto->xf_cnt = transform_cnt[prop_no];
+ TAILQ_INIT(&proto->xfs);
+ for (xf_no = 0; xf_no < proto->xf_cnt; xf_no++) {
+ pa = (struct proto_attr *)calloc(1,
+ sizeof *pa);
+ if (!pa)
+ goto bail_out;
+ pa->len = transform_len[prop_no][xf_no];
+ pa->attrs = (u_int8_t *)malloc(pa->len);
+ if (!pa->attrs) {
+ free(pa);
+ goto bail_out;
+ }
+ memcpy(pa->attrs, transform[prop_no][xf_no],
+ pa->len);
+ TAILQ_INSERT_TAIL(&proto->xfs, pa, next);
+ }
+ TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos,
+ proto, link);
+
+ /* Setup the incoming SPI. */
+ SET_ISAKMP_PROP_SPI_SZ(proposal[prop_no], spi_sz);
+ memcpy(proposal[prop_no] + ISAKMP_PROP_SPI_OFF, spi,
+ spi_sz);
+ proto->spi_sz[1] = spi_sz;
+ proto->spi[1] = spi;
+
+ /*
+ * Let the DOI get at proto for initializing its own
+ * data.
+ */
+ if (doi->proto_init)
+ doi->proto_init(proto, prot->field);
+
+ SET_ISAKMP_PROP_NTRANSFORMS(proposal[prop_no],
+ transform_cnt[prop_no]);
+ prop_no++;
+ }
+ conf_free_list(prot_conf);
+ prot_conf = 0;
+ }
+
+ sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN;
+ sa_buf = malloc(sa_len);
+ if (!sa_buf) {
+ log_error("initiator_send_HASH_SA_NONCE: malloc (%lu) failed",
+ (unsigned long)sa_len);
+ goto bail_out;
+ }
+ SET_ISAKMP_SA_DOI(sa_buf, IPSEC_DOI_IPSEC);
+ SET_IPSEC_SIT_SIT(sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);
+
+ /*
+ * Add the payloads. As this is a SA, we need to recompute the
+ * lengths of the payloads containing others. We also need to
+ * reset these payload's "next payload type" field.
+ */
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
+ goto bail_out;
+ SET_ISAKMP_GEN_LENGTH(sa_buf, sa_len + proposals_len);
+ sa_buf = 0;
+
+ update_nextp = 0;
+ saved_nextp_sa = msg->nextp;
+ for (i = 0; i < prop_no; i++) {
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL,
+ proposal[i], proposal_len, update_nextp))
+ goto bail_out;
+ SET_ISAKMP_GEN_LENGTH(proposal[i],
+ proposal_len + transforms_len[i]);
+ proposal[i] = 0;
+
+ update_nextp = 0;
+ saved_nextp_prop = msg->nextp;
+ for (xf_no = 0; xf_no < transform_cnt[i]; xf_no++) {
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM,
+ transform[i][xf_no],
+ transform_len[i][xf_no], update_nextp))
+ goto bail_out;
+ update_nextp = 1;
+ transform[i][xf_no] = 0;
+ }
+ msg->nextp = saved_nextp_prop;
+ update_nextp = 1;
+ }
+ msg->nextp = saved_nextp_sa;
+
+ /*
+ * Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len.
+ */
+ ie->sa_i_b = message_copy(msg, ISAKMP_GEN_SZ, &ie->sa_i_b_len);
+ if (!ie->sa_i_b)
+ goto bail_out;
+
+ /*
+ * Generate a nonce, and add it to the message.
+ * XXX I want a better way to specify the nonce's size.
+ */
+ if (exchange_gen_nonce(msg, 16))
+ return -1;
+
+ /* Generate optional KEY_EXCH payload. */
+ if (group_desc > 0) {
+ ie->group = group_get(group_desc);
+ ie->g_x_len = dh_getlen(ie->group);
+
+ if (ipsec_gen_g_x(msg)) {
+ group_free(ie->group);
+ ie->group = 0;
+ return -1;
+ }
+ }
+ /* Generate optional client ID payloads. XXX Share with responder. */
+ local_id = conf_get_str(exchange->name, "Local-ID");
+ remote_id = conf_get_str(exchange->name, "Remote-ID");
+ if (local_id && remote_id) {
+ id = ipsec_build_id(local_id, &sz);
+ if (!id)
+ return -1;
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "initiator_send_HASH_SA_NONCE: IDic", id, sz));
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) {
+ free(id);
+ return -1;
+ }
+ id = ipsec_build_id(remote_id, &sz);
+ if (!id)
+ return -1;
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "initiator_send_HASH_SA_NONCE: IDrc", id, sz));
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) {
+ free(id);
+ return -1;
+ }
+ }
+ /* XXX I do not judge these as errors, are they? */
+ else if (local_id)
+ log_print("initiator_send_HASH_SA_NONCE: "
+ "Local-ID given without Remote-ID for \"%s\"",
+ exchange->name);
+ else if (remote_id)
+ /*
+ * This code supports the "road warrior" case, where the
+ * initiator doesn't have a fixed IP address, but wants to
+ * specify a particular remote network to talk to. -- Adrian
+ * Close <adrian@esec.com.au>
+ */
+ {
+ log_print("initiator_send_HASH_SA_NONCE: "
+ "Remote-ID given without Local-ID for \"%s\"",
+ exchange->name);
+
+ /*
+ * If we're here, then we are the initiator, so use initiator
+ * address for local ID
+ */
+ msg->transport->vtbl->get_src(msg->transport, &src);
+ sz = ISAKMP_ID_SZ + sockaddr_addrlen(src);
+
+ id = calloc(sz, sizeof(char));
+ if (!id) {
+ log_error("initiator_send_HASH_SA_NONCE: "
+ "calloc (%lu, %lu) failed", (unsigned long)sz,
+ (unsigned long)sizeof(char));
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET6:
+ SET_ISAKMP_ID_TYPE(id, IPSEC_ID_IPV6_ADDR);
+ break;
+ case AF_INET:
+ SET_ISAKMP_ID_TYPE(id, IPSEC_ID_IPV4_ADDR);
+ break;
+ default:
+ log_error("initiator_send_HASH_SA_NONCE: "
+ "unknown sa_family %d", src->sa_family);
+ free(id);
+ return -1;
+ }
+ memcpy(id + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src),
+ sockaddr_addrlen(src));
+
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "initiator_send_HASH_SA_NONCE: IDic", id, sz));
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) {
+ free(id);
+ return -1;
+ }
+ /* Send supplied remote_id */
+ id = ipsec_build_id(remote_id, &sz);
+ if (!id)
+ return -1;
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "initiator_send_HASH_SA_NONCE: IDrc", id, sz));
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) {
+ free(id);
+ return -1;
+ }
+ }
+ if (ipsec_fill_in_hash(msg))
+ goto bail_out;
+
+ conf_free_list(suite_conf);
+ for (i = 0; i < prop_no; i++) {
+ free(transform[i]);
+ free(transform_len[i]);
+ }
+ free(proposal);
+ free(transform);
+ free(transforms_len);
+ free(transform_len);
+ free(transform_cnt);
+ return 0;
+
+bail_out:
+ if (sa_buf)
+ free(sa_buf);
+ if (proposal) {
+ for (i = 0; i < prop_no; i++) {
+ if (proposal[i])
+ free(proposal[i]);
+ if (transform[i]) {
+ for (xf_no = 0; xf_no < transform_cnt[i];
+ xf_no++)
+ if (transform[i][xf_no])
+ free(transform[i][xf_no]);
+ free(transform[i]);
+ }
+ if (transform_len[i])
+ free(transform_len[i]);
+ }
+ free(proposal);
+ free(transforms_len);
+ free(transform);
+ free(transform_len);
+ free(transform_cnt);
+ }
+ if (xf_conf)
+ conf_free_list(xf_conf);
+ if (prot_conf)
+ conf_free_list(prot_conf);
+ conf_free_list(suite_conf);
+ return -1;
+}
+
+/* Figure out what transform the responder chose. */
+static int
+initiator_recv_HASH_SA_NONCE(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *sa;
+ struct proto *proto, *next_proto;
+ struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA);
+ struct payload *xf, *idp;
+ struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH);
+ struct payload *kep = payload_first(msg, ISAKMP_PAYLOAD_KEY_EXCH);
+ struct prf *prf;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct hash *hash = hash_get(isa->hash);
+ size_t hashsize = hash->hashsize;
+ u_int8_t *rest;
+ size_t rest_len;
+ struct sockaddr *src, *dst;
+
+ /* Allocate the prf and start calculating our HASH(1). XXX Share? */
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: "
+ "SKEYID_a", (u_int8_t *)isa->skeyid_a, isa->skeyid_len));
+ prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf)
+ return -1;
+
+ prf->Init(prf->prfctx);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "initiator_recv_HASH_SA_NONCE: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN));
+ prf->Update(prf->prfctx, exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: "
+ "NONCE_I_b", exchange->nonce_i, exchange->nonce_i_len));
+ prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+ rest = hashp->p + GET_ISAKMP_GEN_LENGTH(hashp->p);
+ rest_len = (GET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base)
+ - (rest - (u_int8_t *)msg->iov[0].iov_base));
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "initiator_recv_HASH_SA_NONCE: payloads after HASH(2)", rest,
+ rest_len));
+ prf->Update(prf->prfctx, rest, rest_len);
+ prf->Final(hash->digest, prf->prfctx);
+ prf_free(prf);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80,
+ "initiator_recv_HASH_SA_NONCE: computed HASH(2)", hash->digest,
+ hashsize));
+ if (memcmp(hashp->p + ISAKMP_HASH_DATA_OFF, hash->digest, hashsize)
+ != 0) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1,
+ 0);
+ return -1;
+ }
+ /* Mark the HASH as handled. */
+ hashp->flags |= PL_MARK;
+
+ /* Mark message as authenticated. */
+ msg->flags |= MSG_AUTHENTICATED;
+
+ /*
+ * As we are getting an answer on our transform offer, only one
+ * transform should be given.
+ *
+ * XXX Currently we only support negotiating one SA per quick mode run.
+ */
+ if (TAILQ_NEXT(sa_p, link)) {
+ log_print("initiator_recv_HASH_SA_NONCE: "
+ "multiple SA payloads in quick mode not supported yet");
+ return -1;
+ }
+ sa = TAILQ_FIRST(&exchange->sa_list);
+
+ /* This is here for the policy check */
+ if (kep)
+ ie->pfs = 1;
+
+ /* Handle optional client ID payloads. */
+ idp = payload_first(msg, ISAKMP_PAYLOAD_ID);
+ if (idp) {
+ /* If IDci is there, IDcr must be too. */
+ if (!TAILQ_NEXT(idp, link)) {
+ /* XXX Is this a good notify type? */
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0,
+ 1, 0);
+ return -1;
+ }
+ /* XXX We should really compare, not override. */
+ ie->id_ci_sz = GET_ISAKMP_GEN_LENGTH(idp->p);
+ ie->id_ci = malloc(ie->id_ci_sz);
+ if (!ie->id_ci) {
+ log_error("initiator_recv_HASH_SA_NONCE: "
+ "malloc (%lu) failed",
+ (unsigned long)ie->id_ci_sz);
+ return -1;
+ }
+ memcpy(ie->id_ci, idp->p, ie->id_ci_sz);
+ idp->flags |= PL_MARK;
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "initiator_recv_HASH_SA_NONCE: IDci",
+ ie->id_ci + ISAKMP_GEN_SZ, ie->id_ci_sz - ISAKMP_GEN_SZ));
+
+ idp = TAILQ_NEXT(idp, link);
+ ie->id_cr_sz = GET_ISAKMP_GEN_LENGTH(idp->p);
+ ie->id_cr = malloc(ie->id_cr_sz);
+ if (!ie->id_cr) {
+ log_error("initiator_recv_HASH_SA_NONCE: "
+ "malloc (%lu) failed",
+ (unsigned long)ie->id_cr_sz);
+ return -1;
+ }
+ memcpy(ie->id_cr, idp->p, ie->id_cr_sz);
+ idp->flags |= PL_MARK;
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "initiator_recv_HASH_SA_NONCE: IDcr",
+ ie->id_cr + ISAKMP_GEN_SZ, ie->id_cr_sz - ISAKMP_GEN_SZ));
+ } else {
+ /*
+ * If client identifiers are not present in the exchange,
+ * we fake them. RFC 2409 states:
+ * The identities of the SAs negotiated in Quick Mode are
+ * implicitly assumed to be the IP addresses of the ISAKMP
+ * peers, without any constraints on the protocol or port
+ * numbers allowed, unless client identifiers are specified
+ * in Quick Mode.
+ *
+ * -- Michael Paddon (mwp@aba.net.au)
+ */
+
+ ie->flags = IPSEC_EXCH_FLAG_NO_ID;
+
+ /* Get initiator and responder addresses. */
+ msg->transport->vtbl->get_src(msg->transport, &src);
+ msg->transport->vtbl->get_dst(msg->transport, &dst);
+ ie->id_ci_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(src);
+ ie->id_cr_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(dst);
+ ie->id_ci = calloc(ie->id_ci_sz, sizeof(char));
+ ie->id_cr = calloc(ie->id_cr_sz, sizeof(char));
+
+ if (!ie->id_ci || !ie->id_cr) {
+ log_error("initiator_recv_HASH_SA_NONCE: "
+ "calloc (%lu, %lu) failed",
+ (unsigned long)ie->id_cr_sz,
+ (unsigned long)sizeof(char));
+ if (ie->id_ci) {
+ free(ie->id_ci);
+ ie->id_ci = 0;
+ }
+ if (ie->id_cr) {
+ free(ie->id_cr);
+ ie->id_cr = 0;
+ }
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ log_error("initiator_recv_HASH_SA_NONCE: "
+ "sa_family mismatch");
+ free(ie->id_ci);
+ ie->id_ci = 0;
+ free(ie->id_cr);
+ ie->id_cr = 0;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV4_ADDR);
+ SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV4_ADDR);
+ break;
+
+ case AF_INET6:
+ SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV6_ADDR);
+ SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV6_ADDR);
+ break;
+
+ default:
+ log_error("initiator_recv_HASH_SA_NONCE: "
+ "unknown sa_family %d", src->sa_family);
+ free(ie->id_ci);
+ ie->id_ci = 0;
+ free(ie->id_cr);
+ ie->id_cr = 0;
+ return -1;
+ }
+ memcpy(ie->id_ci + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src),
+ sockaddr_addrlen(src));
+ memcpy(ie->id_cr + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(dst),
+ sockaddr_addrlen(dst));
+ }
+
+ /* Build the protection suite in our SA. */
+ for (xf = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM); xf;
+ xf = TAILQ_NEXT(xf, link)) {
+
+ /*
+ * XXX We could check that the proposal each transform
+ * belongs to is unique.
+ */
+
+ if (sa_add_transform(sa, xf, exchange->initiator, &proto))
+ return -1;
+
+ /* XXX Check that the chosen transform matches an offer. */
+
+ ipsec_decode_transform(msg, sa, proto, xf->p);
+ }
+
+ /* Now remove offers that we don't need anymore. */
+ for (proto = TAILQ_FIRST(&sa->protos); proto; proto = next_proto) {
+ next_proto = TAILQ_NEXT(proto, link);
+ if (!proto->chosen)
+ proto_free(proto);
+ }
+
+#ifdef USE_POLICY
+ if (!check_policy(exchange, sa, msg->isakmp_sa)) {
+ message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);
+ log_print("initiator_recv_HASH_SA_NONCE: policy check failed");
+ return -1;
+ }
+#endif
+
+ /* Mark the SA as handled. */
+ sa_p->flags |= PL_MARK;
+
+ isa = sa->data;
+ if ((isa->group_desc &&
+ (!ie->group || ie->group->id != isa->group_desc)) ||
+ (!isa->group_desc && ie->group)) {
+ log_print("initiator_recv_HASH_SA_NONCE: disagreement on PFS");
+ return -1;
+ }
+ /* Copy out the initiator's nonce. */
+ if (exchange_save_nonce(msg))
+ return -1;
+
+ /* Handle the optional KEY_EXCH payload. */
+ if (kep && ipsec_save_g_x(msg))
+ return -1;
+
+ return 0;
+}
+
+static int
+initiator_send_HASH(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct prf *prf;
+ u_int8_t *buf;
+ struct hash *hash = hash_get(isa->hash);
+ size_t hashsize = hash->hashsize;
+
+ /*
+ * We want a HASH payload to start with. XXX Share with
+ * ike_main_mode.c?
+ */
+ buf = malloc(ISAKMP_HASH_SZ + hashsize);
+ if (!buf) {
+ log_error("initiator_send_HASH: malloc (%lu) failed",
+ ISAKMP_HASH_SZ + (unsigned long)hashsize);
+ return -1;
+ }
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf,
+ ISAKMP_HASH_SZ + hashsize, 1)) {
+ free(buf);
+ return -1;
+ }
+ /* Allocate the prf and start calculating our HASH(3). XXX Share? */
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: SKEYID_a",
+ isa->skeyid_a, isa->skeyid_len));
+ prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf)
+ return -1;
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, (unsigned char *)"\0", 1);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN));
+ prf->Update(prf->prfctx, exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: NONCE_I_b",
+ exchange->nonce_i, exchange->nonce_i_len));
+ prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: NONCE_R_b",
+ exchange->nonce_r, exchange->nonce_r_len));
+ prf->Update(prf->prfctx, exchange->nonce_r, exchange->nonce_r_len);
+ prf->Final(buf + ISAKMP_GEN_SZ, prf->prfctx);
+ prf_free(prf);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: HASH(3)",
+ buf + ISAKMP_GEN_SZ, hashsize));
+
+ if (ie->group)
+ message_register_post_send(msg, gen_g_xy);
+
+ message_register_post_send(msg, post_quick_mode);
+
+ return 0;
+}
+
+static void
+post_quick_mode(struct message *msg)
+{
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ struct sa *sa;
+ struct proto *proto;
+ struct ipsec_proto *iproto;
+ u_int8_t *keymat;
+ int i;
+
+ /*
+ * Loop over all SA negotiations and do both an in- and an outgoing SA
+ * per protocol.
+ */
+ for (sa = TAILQ_FIRST(&exchange->sa_list); sa;
+ sa = TAILQ_NEXT(sa, next)) {
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link)) {
+ if (proto->proto == IPSEC_PROTO_IPCOMP)
+ continue;
+
+ iproto = proto->data;
+
+ /*
+ * There are two SAs for each SA negotiation,
+ * incoming and outcoing.
+ */
+ for (i = 0; i < 2; i++) {
+ prf = prf_alloc(isa->prf_type, isa->hash,
+ isa->skeyid_d, isa->skeyid_len);
+ if (!prf) {
+ /* XXX What to do? */
+ continue;
+ }
+ ie->keymat_len = ipsec_keymat_length(proto);
+
+ /*
+ * We need to roundup the length of the key
+ * material buffer to a multiple of the PRF's
+ * blocksize as it is generated in chunks of
+ * that blocksize.
+ */
+ iproto->keymat[i]
+ = malloc(((ie->keymat_len + prf->blocksize - 1)
+ / prf->blocksize) * prf->blocksize);
+ if (!iproto->keymat[i]) {
+ log_error("post_quick_mode: "
+ "malloc (%lu) failed",
+ (((unsigned long)ie->keymat_len +
+ prf->blocksize - 1) / prf->blocksize) *
+ prf->blocksize);
+ /* XXX What more to do? */
+ free(prf);
+ continue;
+ }
+ for (keymat = iproto->keymat[i];
+ keymat < iproto->keymat[i] + ie->keymat_len;
+ keymat += prf->blocksize) {
+ prf->Init(prf->prfctx);
+
+ if (keymat != iproto->keymat[i]) {
+ /*
+ * Hash in last round's
+ * KEYMAT.
+ */
+ LOG_DBG_BUF((LOG_NEGOTIATION,
+ 90, "post_quick_mode: "
+ "last KEYMAT",
+ keymat - prf->blocksize,
+ prf->blocksize));
+ prf->Update(prf->prfctx,
+ keymat - prf->blocksize,
+ prf->blocksize);
+ }
+ /* If PFS is used hash in g^xy. */
+ if (ie->g_xy) {
+ LOG_DBG_BUF((LOG_NEGOTIATION,
+ 90, "post_quick_mode: "
+ "g^xy", ie->g_xy,
+ ie->g_x_len));
+ prf->Update(prf->prfctx,
+ ie->g_xy, ie->g_x_len);
+ }
+ LOG_DBG((LOG_NEGOTIATION, 90,
+ "post_quick_mode: "
+ "suite %d proto %d", proto->no,
+ proto->proto));
+ prf->Update(prf->prfctx, &proto->proto,
+ 1);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "post_quick_mode: SPI",
+ proto->spi[i], proto->spi_sz[i]));
+ prf->Update(prf->prfctx,
+ proto->spi[i], proto->spi_sz[i]);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "post_quick_mode: Ni_b",
+ exchange->nonce_i,
+ exchange->nonce_i_len));
+ prf->Update(prf->prfctx,
+ exchange->nonce_i,
+ exchange->nonce_i_len);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "post_quick_mode: Nr_b",
+ exchange->nonce_r,
+ exchange->nonce_r_len));
+ prf->Update(prf->prfctx,
+ exchange->nonce_r,
+ exchange->nonce_r_len);
+ prf->Final(keymat, prf->prfctx);
+ }
+ prf_free(prf);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "post_quick_mode: KEYMAT",
+ iproto->keymat[i], ie->keymat_len));
+ }
+ }
+ }
+
+ log_verbose("isakmpd: quick mode done: %s",
+ !msg->isakmp_sa || !msg->isakmp_sa->transport ? "<no transport>"
+ : msg->isakmp_sa->transport->vtbl->decode_ids
+ (msg->isakmp_sa->transport));
+}
+
+/*
+ * Accept a set of transforms offered by the initiator and chose one we can
+ * handle.
+ * XXX Describe in more detail.
+ */
+static int
+responder_recv_HASH_SA_NONCE(struct message *msg)
+{
+ struct payload *hashp, *kep, *idp;
+ struct sa *sa;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ u_int8_t *hash, *my_hash = 0;
+ size_t hash_len;
+ u_int8_t *pkt = msg->iov[0].iov_base;
+ u_int8_t group_desc = 0;
+ int retval = -1;
+ struct proto *proto;
+ struct sockaddr *src, *dst;
+ char *name;
+
+ hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH);
+ hash = hashp->p;
+ hashp->flags |= PL_MARK;
+
+ /* The HASH payload should be the first one. */
+ if (hash != pkt + ISAKMP_HDR_SZ) {
+ /* XXX Is there a better notification type? */
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
+ goto cleanup;
+ }
+ hash_len = GET_ISAKMP_GEN_LENGTH(hash);
+ my_hash = malloc(hash_len - ISAKMP_GEN_SZ);
+ if (!my_hash) {
+ log_error("responder_recv_HASH_SA_NONCE: malloc (%lu) failed",
+ (unsigned long)hash_len - ISAKMP_GEN_SZ);
+ goto cleanup;
+ }
+ /*
+ * Check the payload's integrity.
+ * XXX Share with ipsec_fill_in_hash?
+ */
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH_SA_NONCE: "
+ "SKEYID_a", isa->skeyid_a, isa->skeyid_len));
+ prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf)
+ goto cleanup;
+ prf->Init(prf->prfctx);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_recv_HASH_SA_NONCE: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN));
+ prf->Update(prf->prfctx, exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_recv_HASH_SA_NONCE: message after HASH",
+ hash + hash_len,
+ msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len));
+ prf->Update(prf->prfctx, hash + hash_len,
+ msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len);
+ prf->Final(my_hash, prf->prfctx);
+ prf_free(prf);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_recv_HASH_SA_NONCE: computed HASH(1)", my_hash,
+ hash_len - ISAKMP_GEN_SZ));
+ if (memcmp(hash + ISAKMP_GEN_SZ, my_hash, hash_len - ISAKMP_GEN_SZ)
+ != 0) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0,
+ 1, 0);
+ goto cleanup;
+ }
+ free(my_hash);
+ my_hash = 0;
+
+ /* Mark message as authenticated. */
+ msg->flags |= MSG_AUTHENTICATED;
+
+ kep = payload_first(msg, ISAKMP_PAYLOAD_KEY_EXCH);
+ if (kep)
+ ie->pfs = 1;
+
+ /* Handle optional client ID payloads. */
+ idp = payload_first(msg, ISAKMP_PAYLOAD_ID);
+ if (idp) {
+ /* If IDci is there, IDcr must be too. */
+ if (!TAILQ_NEXT(idp, link)) {
+ /* XXX Is this a good notify type? */
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0,
+ 1, 0);
+ goto cleanup;
+ }
+ ie->id_ci_sz = GET_ISAKMP_GEN_LENGTH(idp->p);
+ ie->id_ci = malloc(ie->id_ci_sz);
+ if (!ie->id_ci) {
+ log_error("responder_recv_HASH_SA_NONCE: "
+ "malloc (%lu) failed",
+ (unsigned long)ie->id_ci_sz);
+ goto cleanup;
+ }
+ memcpy(ie->id_ci, idp->p, ie->id_ci_sz);
+ idp->flags |= PL_MARK;
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_recv_HASH_SA_NONCE: IDci",
+ ie->id_ci + ISAKMP_GEN_SZ, ie->id_ci_sz - ISAKMP_GEN_SZ));
+
+ idp = TAILQ_NEXT(idp, link);
+ ie->id_cr_sz = GET_ISAKMP_GEN_LENGTH(idp->p);
+ ie->id_cr = malloc(ie->id_cr_sz);
+ if (!ie->id_cr) {
+ log_error("responder_recv_HASH_SA_NONCE: "
+ "malloc (%lu) failed",
+ (unsigned long)ie->id_cr_sz);
+ goto cleanup;
+ }
+ memcpy(ie->id_cr, idp->p, ie->id_cr_sz);
+ idp->flags |= PL_MARK;
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_recv_HASH_SA_NONCE: IDcr",
+ ie->id_cr + ISAKMP_GEN_SZ, ie->id_cr_sz - ISAKMP_GEN_SZ));
+ } else {
+ /*
+ * If client identifiers are not present in the exchange,
+ * we fake them. RFC 2409 states:
+ * The identities of the SAs negotiated in Quick Mode are
+ * implicitly assumed to be the IP addresses of the ISAKMP
+ * peers, without any constraints on the protocol or port
+ * numbers allowed, unless client identifiers are specified
+ * in Quick Mode.
+ *
+ * -- Michael Paddon (mwp@aba.net.au)
+ */
+
+ ie->flags = IPSEC_EXCH_FLAG_NO_ID;
+
+ /* Get initiator and responder addresses. */
+ msg->transport->vtbl->get_src(msg->transport, &src);
+ msg->transport->vtbl->get_dst(msg->transport, &dst);
+ ie->id_ci_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(src);
+ ie->id_cr_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(dst);
+ ie->id_ci = calloc(ie->id_ci_sz, sizeof(char));
+ ie->id_cr = calloc(ie->id_cr_sz, sizeof(char));
+
+ if (!ie->id_ci || !ie->id_cr) {
+ log_error("responder_recv_HASH_SA_NONCE: "
+ "calloc (%lu, %lu) failed",
+ (unsigned long)ie->id_ci_sz,
+ (unsigned long)sizeof(char));
+ goto cleanup;
+ }
+ if (src->sa_family != dst->sa_family) {
+ log_error("initiator_recv_HASH_SA_NONCE: "
+ "sa_family mismatch");
+ goto cleanup;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV4_ADDR);
+ SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV4_ADDR);
+ break;
+
+ case AF_INET6:
+ SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV6_ADDR);
+ SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV6_ADDR);
+ break;
+
+ default:
+ log_error("initiator_recv_HASH_SA_NONCE: "
+ "unknown sa_family %d", src->sa_family);
+ goto cleanup;
+ }
+
+ memcpy(ie->id_cr + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src),
+ sockaddr_addrlen(src));
+ memcpy(ie->id_ci + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(dst),
+ sockaddr_addrlen(dst));
+ }
+
+#ifdef USE_POLICY
+#ifdef USE_KEYNOTE
+ if (message_negotiate_sa(msg, check_policy))
+ goto cleanup;
+#else
+ if (message_negotiate_sa(msg, 0))
+ goto cleanup;
+#endif
+#else
+ if (message_negotiate_sa(msg, 0))
+ goto cleanup;
+#endif /* USE_POLICY */
+
+ for (sa = TAILQ_FIRST(&exchange->sa_list); sa;
+ sa = TAILQ_NEXT(sa, next)) {
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link)) {
+ /*
+ * XXX we need to have some attributes per proto, not
+ * all per SA.
+ */
+ ipsec_decode_transform(msg, sa, proto,
+ proto->chosen->p);
+ if (proto->proto == IPSEC_PROTO_IPSEC_AH
+ && !((struct ipsec_proto *)proto->data)->auth) {
+ log_print("responder_recv_HASH_SA_NONCE: "
+ "AH proposed without an algorithm "
+ "attribute");
+ message_drop(msg,
+ ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);
+ goto next_sa;
+ }
+ }
+
+ isa = sa->data;
+
+ /*
+ * The group description is mandatory if we got a KEY_EXCH
+ * payload.
+ */
+ if (kep) {
+ if (!isa->group_desc) {
+ log_print("responder_recv_HASH_SA_NONCE: "
+ "KEY_EXCH payload without a group "
+ "desc. attribute");
+ message_drop(msg,
+ ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);
+ continue;
+ }
+ /* Also, all SAs must have equal groups. */
+ if (!group_desc)
+ group_desc = isa->group_desc;
+ else if (group_desc != isa->group_desc) {
+ log_print("responder_recv_HASH_SA_NONCE: "
+ "differing group descriptions in one QM");
+ message_drop(msg,
+ ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);
+ continue;
+ }
+ }
+ /* At least one SA was accepted. */
+ retval = 0;
+
+next_sa:
+ ; /* XXX gcc3 wants this. */
+ }
+
+ if (kep) {
+ ie->group = group_get(group_desc);
+ if (!ie->group) {
+ /*
+ * XXX If the error was due to an out-of-range group
+ * description we should notify our peer, but this
+ * should probably be done by the attribute
+ * validation. Is it?
+ */
+ goto cleanup;
+ }
+ }
+ /* Copy out the initiator's nonce. */
+ if (exchange_save_nonce(msg))
+ goto cleanup;
+
+ /* Handle the optional KEY_EXCH payload. */
+ if (kep && ipsec_save_g_x(msg))
+ goto cleanup;
+
+ /*
+ * Try to find and set the connection name on the exchange.
+ */
+
+ /*
+ * Check for accepted identities as well as lookup the connection
+ * name and set it on the exchange.
+ *
+ * When not using policies make sure the peer proposes sane IDs.
+ * Otherwise this is done by KeyNote.
+ */
+ name = connection_passive_lookup_by_ids(ie->id_ci, ie->id_cr);
+ if (name) {
+ exchange->name = strdup(name);
+ if (!exchange->name) {
+ log_error("responder_recv_HASH_SA_NONCE: "
+ "strdup (\"%s\") failed", name);
+ goto cleanup;
+ }
+ } else if (
+#ifdef USE_X509
+ ignore_policy ||
+#endif
+ strncmp("yes", conf_get_str("General", "Use-Keynote"), 3)) {
+ log_print("responder_recv_HASH_SA_NONCE: peer proposed "
+ "invalid phase 2 IDs: %s",
+ (exchange->doi->decode_ids("initiator id %s, responder"
+ " id %s", ie->id_ci, ie->id_ci_sz, ie->id_cr,
+ ie->id_cr_sz, 1)));
+ message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);
+ goto cleanup;
+ }
+
+ return retval;
+
+cleanup:
+ /* Remove all potential protocols that have been added to the SAs. */
+ for (sa = TAILQ_FIRST(&exchange->sa_list); sa;
+ sa = TAILQ_NEXT(sa, next))
+ while ((proto = TAILQ_FIRST(&sa->protos)) != 0)
+ proto_free(proto);
+ if (my_hash)
+ free(my_hash);
+ if (ie->id_ci) {
+ free(ie->id_ci);
+ ie->id_ci = 0;
+ }
+ if (ie->id_cr) {
+ free(ie->id_cr);
+ ie->id_cr = 0;
+ }
+ return -1;
+}
+
+/* Reply with the transform we chose. */
+static int
+responder_send_HASH_SA_NONCE(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct prf *prf;
+ struct hash *hash = hash_get(isa->hash);
+ size_t hashsize = hash->hashsize;
+ size_t nonce_sz = exchange->nonce_i_len;
+ u_int8_t *buf;
+ int initiator = exchange->initiator;
+ char header[80];
+ u_int32_t i;
+ u_int8_t *id;
+ size_t sz;
+
+ /*
+ * We want a HASH payload to start with. XXX Share with
+ * ike_main_mode.c?
+ */
+ buf = malloc(ISAKMP_HASH_SZ + hashsize);
+ if (!buf) {
+ log_error("responder_send_HASH_SA_NONCE: malloc (%lu) failed",
+ ISAKMP_HASH_SZ + (unsigned long)hashsize);
+ return -1;
+ }
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf,
+ ISAKMP_HASH_SZ + hashsize, 1)) {
+ free(buf);
+ return -1;
+ }
+ /* Add the SA payload(s) with the transform(s) that was/were chosen. */
+ if (message_add_sa_payload(msg))
+ return -1;
+
+ /* Generate a nonce, and add it to the message. */
+ if (exchange_gen_nonce(msg, nonce_sz))
+ return -1;
+
+ /* Generate optional KEY_EXCH payload. This is known as PFS. */
+ if (ie->group && ipsec_gen_g_x(msg))
+ return -1;
+
+ /*
+ * If the initiator client ID's were acceptable, just mirror them
+ * back.
+ */
+ if (!(ie->flags & IPSEC_EXCH_FLAG_NO_ID)) {
+ sz = ie->id_ci_sz;
+ id = malloc(sz);
+ if (!id) {
+ log_error("responder_send_HASH_SA_NONCE: "
+ "malloc (%lu) failed", (unsigned long)sz);
+ return -1;
+ }
+ memcpy(id, ie->id_ci, sz);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_send_HASH_SA_NONCE: IDic", id, sz));
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) {
+ free(id);
+ return -1;
+ }
+ sz = ie->id_cr_sz;
+ id = malloc(sz);
+ if (!id) {
+ log_error("responder_send_HASH_SA_NONCE: "
+ "malloc (%lu) failed", (unsigned long)sz);
+ return -1;
+ }
+ memcpy(id, ie->id_cr, sz);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_send_HASH_SA_NONCE: IDrc", id, sz));
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) {
+ free(id);
+ return -1;
+ }
+ }
+ /* Allocate the prf and start calculating our HASH(2). XXX Share? */
+ LOG_DBG((LOG_NEGOTIATION, 90, "responder_recv_HASH: "
+ "isakmp_sa %p isa %p", isakmp_sa, isa));
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_send_HASH_SA_NONCE: "
+ "SKEYID_a", isa->skeyid_a, isa->skeyid_len));
+ prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf)
+ return -1;
+ prf->Init(prf->prfctx);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_send_HASH_SA_NONCE: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN));
+ prf->Update(prf->prfctx, exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_send_HASH_SA_NONCE: "
+ "NONCE_I_b", exchange->nonce_i, exchange->nonce_i_len));
+ prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+
+ /* Loop over all payloads after HASH(2). */
+ for (i = 2; i < msg->iovlen; i++) {
+ /* XXX Misleading payload type printouts. */
+ snprintf(header, sizeof header,
+ "responder_send_HASH_SA_NONCE: payload %d after HASH(2)",
+ i - 1);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, header, msg->iov[i].iov_base,
+ msg->iov[i].iov_len));
+ prf->Update(prf->prfctx, msg->iov[i].iov_base,
+ msg->iov[i].iov_len);
+ }
+ prf->Final(buf + ISAKMP_HASH_DATA_OFF, prf->prfctx);
+ prf_free(prf);
+ snprintf(header, sizeof header, "responder_send_HASH_SA_NONCE: "
+ "HASH_%c", initiator ? 'I' : 'R');
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80, header, buf + ISAKMP_HASH_DATA_OFF,
+ hashsize));
+
+ if (ie->group)
+ message_register_post_send(msg, gen_g_xy);
+
+ return 0;
+}
+
+static void
+gen_g_xy(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+
+ /* Compute Diffie-Hellman shared value. */
+ ie->g_xy = malloc(ie->g_x_len);
+ if (!ie->g_xy) {
+ log_error("gen_g_xy: malloc (%lu) failed",
+ (unsigned long)ie->g_x_len);
+ return;
+ }
+ if (dh_create_shared(ie->group, ie->g_xy,
+ exchange->initiator ? ie->g_xr : ie->g_xi)) {
+ log_print("gen_g_xy: dh_create_shared failed");
+ return;
+ }
+ LOG_DBG_BUF((LOG_NEGOTIATION, 80, "gen_g_xy: g^xy", ie->g_xy,
+ ie->g_x_len));
+}
+
+static int
+responder_recv_HASH(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct prf *prf;
+ u_int8_t *hash, *my_hash = 0;
+ size_t hash_len;
+ struct payload *hashp;
+
+ /* Find HASH(3) and create our own hash, just as big. */
+ hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH);
+ hash = hashp->p;
+ hashp->flags |= PL_MARK;
+ hash_len = GET_ISAKMP_GEN_LENGTH(hash);
+ my_hash = malloc(hash_len - ISAKMP_GEN_SZ);
+ if (!my_hash) {
+ log_error("responder_recv_HASH: malloc (%lu) failed",
+ (unsigned long)hash_len - ISAKMP_GEN_SZ);
+ goto cleanup;
+ }
+ /* Allocate the prf and start calculating our HASH(3). XXX Share? */
+ LOG_DBG((LOG_NEGOTIATION, 90, "responder_recv_HASH: "
+ "isakmp_sa %p isa %p", isakmp_sa, isa));
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: SKEYID_a",
+ isa->skeyid_a, isa->skeyid_len));
+ prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf)
+ goto cleanup;
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, (unsigned char *)"\0", 1);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN));
+ prf->Update(prf->prfctx, exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: NONCE_I_b",
+ exchange->nonce_i, exchange->nonce_i_len));
+ prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: NONCE_R_b",
+ exchange->nonce_r, exchange->nonce_r_len));
+ prf->Update(prf->prfctx, exchange->nonce_r, exchange->nonce_r_len);
+ prf->Final(my_hash, prf->prfctx);
+ prf_free(prf);
+ LOG_DBG_BUF((LOG_NEGOTIATION, 90,
+ "responder_recv_HASH: computed HASH(3)", my_hash,
+ hash_len - ISAKMP_GEN_SZ));
+ if (memcmp(hash + ISAKMP_GEN_SZ, my_hash, hash_len - ISAKMP_GEN_SZ)
+ != 0) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0,
+ 1, 0);
+ goto cleanup;
+ }
+ free(my_hash);
+
+ /* Mark message as authenticated. */
+ msg->flags |= MSG_AUTHENTICATED;
+
+ post_quick_mode(msg);
+
+ return 0;
+
+cleanup:
+ if (my_hash)
+ free(my_hash);
+ return -1;
+}
diff --git a/keyexchange/isakmpd-20041012/ike_quick_mode.h b/keyexchange/isakmpd-20041012/ike_quick_mode.h
new file mode 100644
index 0000000..32b1523
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ike_quick_mode.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: ike_quick_mode.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: ike_quick_mode.h,v 1.1 1998/08/02 20:22:44 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IKE_QUICK_MODE_H_
+#define _IKE_QUICK_MODE_H_
+
+struct message;
+
+extern int (*ike_quick_mode_initiator[]) (struct message *);
+extern int (*ike_quick_mode_responder[]) (struct message *);
+
+#endif /* _IKE_QUICK_MODE_H_ */
diff --git a/keyexchange/isakmpd-20041012/init.c b/keyexchange/isakmpd-20041012/init.c
new file mode 100644
index 0000000..5ee6682
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/init.c
@@ -0,0 +1,158 @@
+/* $OpenBSD: init.c,v 1.33 2004/09/17 13:46:34 ho Exp $ */
+/* $EOM: init.c,v 1.25 2000/03/30 14:27:24 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2003, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/* XXX This file could easily be built dynamically instead. */
+
+#include <stdlib.h>
+
+#include "sysdep.h"
+
+#include "app.h"
+#include "cert.h"
+#include "conf.h"
+#include "connection.h"
+#include "doi.h"
+#include "exchange.h"
+#include "init.h"
+#include "ipsec.h"
+#include "isakmp_doi.h"
+#include "libcrypto.h"
+#include "log.h"
+#include "math_group.h"
+#include "monitor.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "virtual.h"
+#include "udp.h"
+#include "ui.h"
+#include "util.h"
+
+#if defined (USE_POLICY)
+#include "policy.h"
+#endif
+
+#if defined (USE_NAT_TRAVERSAL)
+#include "nat_traversal.h"
+#include "udp_encap.h"
+#endif
+
+void
+init(void)
+{
+ app_init();
+ doi_init();
+ exchange_init();
+ group_init();
+ ipsec_init();
+ isakmp_doi_init();
+ message_init();
+ libcrypto_init();
+
+ timer_init();
+
+ /* The following group are depending on timer_init having run. */
+ conf_init();
+ connection_init();
+
+ /* This depends on conf_init, thus check as soon as possible. */
+ log_reinit();
+
+#if defined (USE_POLICY)
+ /* policy_init depends on conf_init having run. */
+ policy_init();
+#endif
+
+ /* Depends on conf_init and policy_init having run */
+ cert_init();
+ crl_init();
+
+ sa_init();
+ transport_init();
+ virtual_init();
+ udp_init();
+#if defined (USE_NAT_TRAVERSAL)
+ nat_t_init();
+ udp_encap_init();
+#endif
+ monitor_ui_init();
+}
+
+/* Reinitialize, either after a SIGHUP reception or by FIFO UI cmd. */
+void
+reinit(void)
+{
+ log_print("isakmpd: reinitializing daemon");
+
+ /*
+ * XXX Remove all(/some?) pending exchange timers? - they may not be
+ * possible to complete after we've re-read the config file.
+ * User-initiated SIGHUP's maybe "authorizes" a wait until
+ * next connection-check.
+ * XXX This means we discard exchange->last_msg, is this really ok?
+ */
+
+ /* Reinitialize PRNG if we are in deterministic mode. */
+ if (regrand)
+ srandom(seed);
+
+ /* Reread config file. */
+ conf_reinit();
+
+ log_reinit();
+
+#if defined (USE_POLICY)
+ /* Reread the policies. */
+ policy_init();
+#endif
+
+ /* Reinitialize certificates */
+ cert_init();
+ crl_init();
+
+ /* Reinitialize our connection list. */
+ connection_reinit();
+
+ /*
+ * Rescan interfaces (call reinit() in all transports).
+ */
+ transport_reinit();
+
+ /*
+ * XXX "These" (non-existent) reinitializations should not be done.
+ * cookie_reinit ();
+ * ui_reinit ();
+ */
+
+ sa_reinit();
+}
diff --git a/keyexchange/isakmpd-20041012/init.h b/keyexchange/isakmpd-20041012/init.h
new file mode 100644
index 0000000..cbcd46a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/init.h
@@ -0,0 +1,38 @@
+/* $OpenBSD: init.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: init.h,v 1.2 1998/07/07 23:36:00 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _INIT_H_
+#define _INIT_H_
+
+extern void init(void);
+extern void reinit(void);
+
+#endif /* _INIT_H_ */
diff --git a/keyexchange/isakmpd-20041012/ipsec.c b/keyexchange/isakmpd-20041012/ipsec.c
new file mode 100644
index 0000000..46cb8d9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ipsec.c
@@ -0,0 +1,2523 @@
+/* $OpenBSD: ipsec.c,v 1.104 2004/09/17 13:53:08 ho Exp $ */
+/* $EOM: ipsec.c,v 1.143 2000/12/11 23:57:42 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "conf.h"
+#include "constants.h"
+#include "crypto.h"
+#include "dh.h"
+#include "doi.h"
+#if defined (USE_DPD)
+#include "dpd.h"
+#endif
+#include "exchange.h"
+#include "hash.h"
+#include "ike_aggressive.h"
+#include "ike_auth.h"
+#include "ike_main_mode.h"
+#include "ike_quick_mode.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "isakmp.h"
+#include "isakmp_cfg.h"
+#include "isakmp_fld.h"
+#include "isakmp_num.h"
+#include "log.h"
+#include "math_group.h"
+#include "message.h"
+#if defined (USE_NAT_TRAVERSAL)
+#include "nat_traversal.h"
+#endif
+#include "prf.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+#ifdef USE_X509
+#include "x509.h"
+#endif
+
+extern int acquire_only;
+
+/* Backwards compatibility. */
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+
+/* The replay window size used for all IPsec protocols if not overridden. */
+#define DEFAULT_REPLAY_WINDOW 16
+
+struct ipsec_decode_arg {
+ struct message *msg;
+ struct sa *sa;
+ struct proto *proto;
+};
+
+/* These variables hold the contacted peers ADT state. */
+struct contact {
+ struct sockaddr *addr;
+ socklen_t len;
+} *contacts = 0;
+int contact_cnt = 0, contact_limit = 0;
+
+static int addr_cmp(const void *, const void *);
+static int ipsec_add_contact(struct message *);
+static int ipsec_contacted(struct message *);
+#ifdef USE_DEBUG
+static int ipsec_debug_attribute(u_int16_t, u_int8_t *, u_int16_t,
+ void *);
+#endif
+static void ipsec_delete_spi(struct sa *, struct proto *, int);
+static int16_t *ipsec_exchange_script(u_int8_t);
+static void ipsec_finalize_exchange(struct message *);
+static void ipsec_free_exchange_data(void *);
+static void ipsec_free_proto_data(void *);
+static void ipsec_free_sa_data(void *);
+static struct keystate *ipsec_get_keystate(struct message *);
+static u_int8_t *ipsec_get_spi(size_t *, u_int8_t, struct message *);
+static int ipsec_handle_leftover_payload(struct message *, u_int8_t,
+ struct payload *);
+static int ipsec_informational_post_hook(struct message *);
+static int ipsec_informational_pre_hook(struct message *);
+static int ipsec_initiator(struct message *);
+static void ipsec_proto_init(struct proto *, char *);
+static int ipsec_responder(struct message *);
+static void ipsec_setup_situation(u_int8_t *);
+static int ipsec_set_network(u_int8_t *, u_int8_t *, struct ipsec_sa *);
+static size_t ipsec_situation_size(void);
+static u_int8_t ipsec_spi_size(u_int8_t);
+static int ipsec_validate_attribute(u_int16_t, u_int8_t *, u_int16_t,
+ void *);
+static int ipsec_validate_exchange(u_int8_t);
+static int ipsec_validate_id_information(u_int8_t, u_int8_t *, u_int8_t *,
+ size_t, struct exchange *);
+static int ipsec_validate_key_information(u_int8_t *, size_t);
+static int ipsec_validate_notification(u_int16_t);
+static int ipsec_validate_proto(u_int8_t);
+static int ipsec_validate_situation(u_int8_t *, size_t *, size_t);
+static int ipsec_validate_transform_id(u_int8_t, u_int8_t);
+
+static struct doi ipsec_doi = {
+ {0}, IPSEC_DOI_IPSEC,
+ sizeof(struct ipsec_exch), sizeof(struct ipsec_sa),
+ sizeof(struct ipsec_proto),
+#ifdef USE_DEBUG
+ ipsec_debug_attribute,
+#endif
+ ipsec_delete_spi,
+ ipsec_exchange_script,
+ ipsec_finalize_exchange,
+ ipsec_free_exchange_data,
+ ipsec_free_proto_data,
+ ipsec_free_sa_data,
+ ipsec_get_keystate,
+ ipsec_get_spi,
+ ipsec_handle_leftover_payload,
+ ipsec_informational_post_hook,
+ ipsec_informational_pre_hook,
+ ipsec_is_attribute_incompatible,
+ ipsec_proto_init,
+ ipsec_setup_situation,
+ ipsec_situation_size,
+ ipsec_spi_size,
+ ipsec_validate_attribute,
+ ipsec_validate_exchange,
+ ipsec_validate_id_information,
+ ipsec_validate_key_information,
+ ipsec_validate_notification,
+ ipsec_validate_proto,
+ ipsec_validate_situation,
+ ipsec_validate_transform_id,
+ ipsec_initiator,
+ ipsec_responder,
+ ipsec_decode_ids
+};
+
+int16_t script_quick_mode[] = {
+ ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_SA,
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_SA,
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_END
+};
+
+int16_t script_new_group_mode[] = {
+ ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_SA,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_SA,
+ EXCHANGE_SCRIPT_END
+};
+
+struct dst_spi_proto_arg {
+ struct sockaddr *dst;
+ u_int32_t spi;
+ u_int8_t proto;
+};
+
+/*
+ * Check if SA matches what we are asking for through V_ARG. It has to
+ * be a finished phase 2 SA.
+ * if "proto" arg is 0, match any proto
+ */
+static int
+ipsec_sa_check(struct sa *sa, void *v_arg)
+{
+ struct dst_spi_proto_arg *arg = v_arg;
+ struct proto *proto;
+ struct sockaddr *dst, *src;
+ int incoming;
+
+ if (sa->phase != 2 || !(sa->flags & SA_FLAG_READY))
+ return 0;
+
+ sa->transport->vtbl->get_dst(sa->transport, &dst);
+ if (memcmp(sockaddr_addrdata(dst), sockaddr_addrdata(arg->dst),
+ sockaddr_addrlen(dst)) == 0)
+ incoming = 0;
+ else {
+ sa->transport->vtbl->get_src(sa->transport, &src);
+ if (memcmp(sockaddr_addrdata(src), sockaddr_addrdata(arg->dst),
+ sockaddr_addrlen(src)) == 0)
+ incoming = 1;
+ else
+ return 0;
+ }
+
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link))
+ if ((arg->proto == 0 || proto->proto == arg->proto) &&
+ memcmp(proto->spi[incoming], &arg->spi, sizeof arg->spi)
+ == 0)
+ return 1;
+ return 0;
+}
+
+/* Find an SA with a "name" of DST, SPI & PROTO. */
+struct sa *
+ipsec_sa_lookup(struct sockaddr *dst, u_int32_t spi, u_int8_t proto)
+{
+ struct dst_spi_proto_arg arg;
+
+ arg.dst = dst;
+ arg.spi = spi;
+ arg.proto = proto;
+ return sa_find(ipsec_sa_check, &arg);
+}
+
+/*
+ * Check if SA matches the flow of another SA in V_ARG. It has to
+ * be a finished non-replaced phase 2 SA.
+ * XXX At some point other selectors will matter here too.
+ */
+static int
+ipsec_sa_check_flow(struct sa *sa, void *v_arg)
+{
+ struct sa *sa2 = v_arg;
+ struct ipsec_sa *isa = sa->data, *isa2 = sa2->data;
+
+ if (sa == sa2 || sa->phase != 2 ||
+ (sa->flags & (SA_FLAG_READY | SA_FLAG_REPLACED)) != SA_FLAG_READY)
+ return 0;
+
+ if (isa->tproto != isa2->tproto || isa->sport != isa2->sport ||
+ isa->dport != isa2->dport)
+ return 0;
+
+ return isa->src_net->sa_family == isa2->src_net->sa_family &&
+ memcmp(sockaddr_addrdata(isa->src_net),
+ sockaddr_addrdata(isa2->src_net),
+ sockaddr_addrlen(isa->src_net)) == 0 &&
+ memcmp(sockaddr_addrdata(isa->src_mask),
+ sockaddr_addrdata(isa2->src_mask),
+ sockaddr_addrlen(isa->src_mask)) == 0 &&
+ memcmp(sockaddr_addrdata(isa->dst_net),
+ sockaddr_addrdata(isa2->dst_net),
+ sockaddr_addrlen(isa->dst_net)) == 0 &&
+ memcmp(sockaddr_addrdata(isa->dst_mask),
+ sockaddr_addrdata(isa2->dst_mask),
+ sockaddr_addrlen(isa->dst_mask)) == 0;
+}
+
+/*
+ * Do IPsec DOI specific finalizations task for the exchange where MSG was
+ * the final message.
+ */
+static void
+ipsec_finalize_exchange(struct message *msg)
+{
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *sa = 0, *old_sa;
+ struct proto *proto, *last_proto = 0;
+#ifdef USE_DEBUG
+ char *addr1, *addr2, *mask1, *mask2;
+#endif
+
+ switch (exchange->phase) {
+ case 1:
+ switch (exchange->type) {
+ case ISAKMP_EXCH_ID_PROT:
+ case ISAKMP_EXCH_AGGRESSIVE:
+ isa = isakmp_sa->data;
+ isa->hash = ie->hash->type;
+ isa->prf_type = ie->prf_type;
+ isa->skeyid_len = ie->skeyid_len;
+ isa->skeyid_d = ie->skeyid_d;
+ isa->skeyid_a = ie->skeyid_a;
+ /* Prevents early free of SKEYID_*. */
+ ie->skeyid_a = ie->skeyid_d = 0;
+
+ /*
+ * If a lifetime was negotiated setup the expiration
+ * timers.
+ */
+ if (isakmp_sa->seconds)
+ sa_setup_expirations(isakmp_sa);
+
+#if defined (USE_NAT_TRAVERSAL)
+ if (isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE)
+ nat_t_setup_keepalive(isakmp_sa);
+#endif
+ break;
+ }
+ break;
+
+ case 2:
+ switch (exchange->type) {
+ case IKE_EXCH_QUICK_MODE:
+ /*
+ * Tell the application(s) about the SPIs and key
+ * material.
+ */
+ for (sa = TAILQ_FIRST(&exchange->sa_list); sa;
+ sa = TAILQ_NEXT(sa, next)) {
+ isa = sa->data;
+
+ if (exchange->initiator) {
+ /*
+ * Initiator is source, responder is
+ * destination.
+ */
+ if (ipsec_set_network(ie->id_ci,
+ ie->id_cr, isa)) {
+ log_print(
+ "ipsec_finalize_exchange: "
+ "ipsec_set_network "
+ "failed");
+ return;
+ }
+ } else {
+ /*
+ * Responder is source, initiator is
+ * destination.
+ */
+ if (ipsec_set_network(ie->id_cr,
+ ie->id_ci, isa)) {
+ log_print(
+ "ipsec_finalize_exchange: "
+ "ipsec_set_network "
+ "failed");
+ return;
+ }
+ }
+
+ for (proto = TAILQ_FIRST(&sa->protos),
+ last_proto = 0; proto;
+ proto = TAILQ_NEXT(proto, link)) {
+ if (sysdep_ipsec_set_spi(sa, proto,
+ 0, isakmp_sa) ||
+ (last_proto &&
+ sysdep_ipsec_group_spis(sa,
+ last_proto, proto, 0)) ||
+ sysdep_ipsec_set_spi(sa, proto,
+ 1, isakmp_sa) ||
+ (last_proto &&
+ sysdep_ipsec_group_spis(sa,
+ last_proto, proto, 1)))
+ /*
+ * XXX Tear down this
+ * exchange.
+ */
+ return;
+ last_proto = proto;
+ }
+
+#ifdef USE_DEBUG
+ if (sockaddr2text(isa->src_net, &addr1, 0))
+ addr1 = 0;
+ if (sockaddr2text(isa->src_mask, &mask1, 0))
+ mask1 = 0;
+ if (sockaddr2text(isa->dst_net, &addr2, 0))
+ addr2 = 0;
+ if (sockaddr2text(isa->dst_mask, &mask2, 0))
+ mask2 = 0;
+
+ LOG_DBG((LOG_EXCHANGE, 50,
+ "ipsec_finalize_exchange: src %s %s "
+ "dst %s %s tproto %u sport %u dport %u",
+ addr1 ? addr1 : "<??\?>",
+ mask1 ? mask1 : "<??\?>",
+ addr2 ? addr2 : "<??\?>",
+ mask2 ? mask2 : "<??\?>",
+ isa->tproto, ntohs(isa->sport),
+ ntohs(isa->dport)));
+
+ if (addr1)
+ free(addr1);
+ if (mask1)
+ free(mask1);
+ if (addr2)
+ free(addr2);
+ if (mask2)
+ free(mask2);
+
+#endif /* USE_DEBUG */
+
+ /*
+ * If this is not an SA acquired by the
+ * kernel, it needs to have a SPD entry
+ * (a.k.a. flow) set up.
+ */
+ if (!(sa->flags & SA_FLAG_ONDEMAND ||
+ conf_get_str("General", "Acquire-Only")
+ || acquire_only)
+ && sysdep_ipsec_enable_sa(sa, isakmp_sa))
+ /* XXX Tear down this exchange. */
+ return;
+
+ /*
+ * Mark elder SAs with the same flow
+ * information as replaced.
+ */
+ while ((old_sa = sa_find(ipsec_sa_check_flow,
+ sa)) != 0)
+ sa_mark_replaced(old_sa);
+ }
+ break;
+ }
+ }
+}
+
+/* Set the client addresses in ISA from SRC_ID and DST_ID. */
+static int
+ipsec_set_network(u_int8_t *src_id, u_int8_t *dst_id, struct ipsec_sa *isa)
+{
+ int id;
+
+ /* Set source address/mask. */
+ id = GET_ISAKMP_ID_TYPE(src_id);
+ switch (id) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ isa->src_net = (struct sockaddr *)calloc(1,
+ sizeof(struct sockaddr_in));
+ if (!isa->src_net)
+ goto memfail;
+ isa->src_net->sa_family = AF_INET;
+#ifndef USE_OLD_SOCKADDR
+ isa->src_net->sa_len = sizeof(struct sockaddr_in);
+#endif
+
+ isa->src_mask = (struct sockaddr *)calloc(1,
+ sizeof(struct sockaddr_in));
+ if (!isa->src_mask)
+ goto memfail;
+ isa->src_mask->sa_family = AF_INET;
+#ifndef USE_OLD_SOCKADDR
+ isa->src_mask->sa_len = sizeof(struct sockaddr_in);
+#endif
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ isa->src_net = (struct sockaddr *)calloc(1,
+ sizeof(struct sockaddr_in6));
+ if (!isa->src_net)
+ goto memfail;
+ isa->src_net->sa_family = AF_INET6;
+#ifndef USE_OLD_SOCKADDR
+ isa->src_net->sa_len = sizeof(struct sockaddr_in6);
+#endif
+
+ isa->src_mask = (struct sockaddr *)calloc(1,
+ sizeof(struct sockaddr_in6));
+ if (!isa->src_mask)
+ goto memfail;
+ isa->src_mask->sa_family = AF_INET6;
+#ifndef USE_OLD_SOCKADDR
+ isa->src_mask->sa_len = sizeof(struct sockaddr_in6);
+#endif
+ break;
+
+ case IPSEC_ID_IPV4_RANGE:
+ case IPSEC_ID_IPV6_RANGE:
+ case IPSEC_ID_DER_ASN1_DN:
+ case IPSEC_ID_DER_ASN1_GN:
+ case IPSEC_ID_KEY_ID:
+ default:
+ log_print("ipsec_set_network: ID type %d (%s) not supported",
+ id, constant_name(ipsec_id_cst, id));
+ return -1;
+ }
+
+ /* Net */
+ memcpy(sockaddr_addrdata(isa->src_net), src_id + ISAKMP_ID_DATA_OFF,
+ sockaddr_addrlen(isa->src_net));
+
+ /* Mask */
+ switch (id) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV6_ADDR:
+ memset(sockaddr_addrdata(isa->src_mask), 0xff,
+ sockaddr_addrlen(isa->src_mask));
+ break;
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ memcpy(sockaddr_addrdata(isa->src_mask), src_id +
+ ISAKMP_ID_DATA_OFF + sockaddr_addrlen(isa->src_net),
+ sockaddr_addrlen(isa->src_mask));
+ break;
+ }
+
+ memcpy(&isa->sport,
+ src_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF,
+ IPSEC_ID_PORT_LEN);
+
+ /* Set destination address. */
+ id = GET_ISAKMP_ID_TYPE(dst_id);
+ switch (id) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ isa->dst_net = (struct sockaddr *)calloc(1,
+ sizeof(struct sockaddr_in));
+ if (!isa->dst_net)
+ goto memfail;
+ isa->dst_net->sa_family = AF_INET;
+#ifndef USE_OLD_SOCKADDR
+ isa->dst_net->sa_len = sizeof(struct sockaddr_in);
+#endif
+
+ isa->dst_mask = (struct sockaddr *)calloc(1,
+ sizeof(struct sockaddr_in));
+ if (!isa->dst_mask)
+ goto memfail;
+ isa->dst_mask->sa_family = AF_INET;
+#ifndef USE_OLD_SOCKADDR
+ isa->dst_mask->sa_len = sizeof(struct sockaddr_in);
+#endif
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ isa->dst_net = (struct sockaddr *)calloc(1,
+ sizeof(struct sockaddr_in6));
+ if (!isa->dst_net)
+ goto memfail;
+ isa->dst_net->sa_family = AF_INET6;
+#ifndef USE_OLD_SOCKADDR
+ isa->dst_net->sa_len = sizeof(struct sockaddr_in6);
+#endif
+
+ isa->dst_mask = (struct sockaddr *)calloc(1,
+ sizeof(struct sockaddr_in6));
+ if (!isa->dst_mask)
+ goto memfail;
+ isa->dst_mask->sa_family = AF_INET6;
+#ifndef USE_OLD_SOCKADDR
+ isa->dst_mask->sa_len = sizeof(struct sockaddr_in6);
+#endif
+ break;
+ }
+
+ /* Net */
+ memcpy(sockaddr_addrdata(isa->dst_net), dst_id + ISAKMP_ID_DATA_OFF,
+ sockaddr_addrlen(isa->dst_net));
+
+ /* Mask */
+ switch (id) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV6_ADDR:
+ memset(sockaddr_addrdata(isa->dst_mask), 0xff,
+ sockaddr_addrlen(isa->dst_mask));
+ break;
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ memcpy(sockaddr_addrdata(isa->dst_mask), dst_id +
+ ISAKMP_ID_DATA_OFF + sockaddr_addrlen(isa->dst_net),
+ sockaddr_addrlen(isa->dst_mask));
+ break;
+ }
+
+ memcpy(&isa->tproto, dst_id + ISAKMP_ID_DOI_DATA_OFF +
+ IPSEC_ID_PROTO_OFF, IPSEC_ID_PROTO_LEN);
+ memcpy(&isa->dport,
+ dst_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF,
+ IPSEC_ID_PORT_LEN);
+ return 0;
+
+memfail:
+ log_error("ipsec_set_network: calloc () failed");
+ return -1;
+}
+
+/* Free the DOI-specific exchange data pointed to by VIE. */
+static void
+ipsec_free_exchange_data(void *vie)
+{
+ struct ipsec_exch *ie = vie;
+#ifdef USE_ISAKMP_CFG
+ struct isakmp_cfg_attr *attr;
+#endif
+
+ if (ie->sa_i_b)
+ free(ie->sa_i_b);
+ if (ie->id_ci)
+ free(ie->id_ci);
+ if (ie->id_cr)
+ free(ie->id_cr);
+ if (ie->g_xi)
+ free(ie->g_xi);
+ if (ie->g_xr)
+ free(ie->g_xr);
+ if (ie->g_xy)
+ free(ie->g_xy);
+ if (ie->skeyid)
+ free(ie->skeyid);
+ if (ie->skeyid_d)
+ free(ie->skeyid_d);
+ if (ie->skeyid_a)
+ free(ie->skeyid_a);
+ if (ie->skeyid_e)
+ free(ie->skeyid_e);
+ if (ie->hash_i)
+ free(ie->hash_i);
+ if (ie->hash_r)
+ free(ie->hash_r);
+ if (ie->group)
+ group_free(ie->group);
+#ifdef USE_ISAKMP_CFG
+ for (attr = LIST_FIRST(&ie->attrs); attr;
+ attr = LIST_FIRST(&ie->attrs)) {
+ LIST_REMOVE(attr, link);
+ if (attr->length)
+ free(attr->value);
+ free(attr);
+ }
+#endif
+}
+
+/* Free the DOI-specific SA data pointed to by VISA. */
+static void
+ipsec_free_sa_data(void *visa)
+{
+ struct ipsec_sa *isa = visa;
+
+ if (isa->src_net)
+ free(isa->src_net);
+ if (isa->src_mask)
+ free(isa->src_mask);
+ if (isa->dst_net)
+ free(isa->dst_net);
+ if (isa->dst_mask)
+ free(isa->dst_mask);
+ if (isa->skeyid_a)
+ free(isa->skeyid_a);
+ if (isa->skeyid_d)
+ free(isa->skeyid_d);
+}
+
+/* Free the DOI-specific protocol data of an SA pointed to by VIPROTO. */
+static void
+ipsec_free_proto_data(void *viproto)
+{
+ struct ipsec_proto *iproto = viproto;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (iproto->keymat[i])
+ free(iproto->keymat[i]);
+}
+
+/* Return exchange script based on TYPE. */
+static int16_t *
+ipsec_exchange_script(u_int8_t type)
+{
+ switch (type) {
+#ifdef USE_ISAKMP_CFG
+ case ISAKMP_EXCH_TRANSACTION:
+ return script_transaction;
+#endif
+ case IKE_EXCH_QUICK_MODE:
+ return script_quick_mode;
+ case IKE_EXCH_NEW_GROUP_MODE:
+ return script_new_group_mode;
+ }
+ return 0;
+}
+
+/* Initialize this DOI, requires doi_init to already have been called. */
+void
+ipsec_init(void)
+{
+ doi_register(&ipsec_doi);
+}
+
+/* Given a message MSG, return a suitable IV (or rather keystate). */
+static struct keystate *
+ipsec_get_keystate(struct message *msg)
+{
+ struct keystate *ks;
+ struct hash *hash;
+
+ /* If we have already have an IV, use it. */
+ if (msg->exchange && msg->exchange->keystate) {
+ ks = malloc(sizeof *ks);
+ if (!ks) {
+ log_error("ipsec_get_keystate: malloc (%lu) failed",
+ (unsigned long) sizeof *ks);
+ return 0;
+ }
+ memcpy(ks, msg->exchange->keystate, sizeof *ks);
+ return ks;
+ }
+ /*
+ * For phase 2 when no SA yet is setup we need to hash the IV used by
+ * the ISAKMP SA concatenated with the message ID, and use that as an
+ * IV for further cryptographic operations.
+ */
+ if (!msg->isakmp_sa->keystate) {
+ log_print("ipsec_get_keystate: no keystate in ISAKMP SA %p",
+ msg->isakmp_sa);
+ return 0;
+ }
+ ks = crypto_clone_keystate(msg->isakmp_sa->keystate);
+ if (!ks)
+ return 0;
+
+ hash = hash_get(((struct ipsec_sa *)msg->isakmp_sa->data)->hash);
+ hash->Init(hash->ctx);
+ LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: final phase 1 IV",
+ ks->riv, ks->xf->blocksize));
+ hash->Update(hash->ctx, ks->riv, ks->xf->blocksize);
+ LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: message ID",
+ ((u_int8_t *) msg->iov[0].iov_base) + ISAKMP_HDR_MESSAGE_ID_OFF,
+ ISAKMP_HDR_MESSAGE_ID_LEN));
+ hash->Update(hash->ctx, ((u_int8_t *) msg->iov[0].iov_base) +
+ ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN);
+ hash->Final(hash->digest, hash->ctx);
+ crypto_init_iv(ks, hash->digest, ks->xf->blocksize);
+ LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: phase 2 IV",
+ hash->digest, ks->xf->blocksize));
+ return ks;
+}
+
+static void
+ipsec_setup_situation(u_int8_t *buf)
+{
+ SET_IPSEC_SIT_SIT(buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);
+}
+
+static size_t
+ipsec_situation_size(void)
+{
+ return IPSEC_SIT_SIT_LEN;
+}
+
+static u_int8_t
+ipsec_spi_size(u_int8_t proto)
+{
+ return IPSEC_SPI_SIZE;
+}
+
+static int
+ipsec_validate_attribute(u_int16_t type, u_int8_t * value, u_int16_t len,
+ void *vmsg)
+{
+ struct message *msg = vmsg;
+
+ if ((msg->exchange->phase == 1
+ && (type < IKE_ATTR_ENCRYPTION_ALGORITHM
+ || type > IKE_ATTR_GROUP_ORDER))
+ || (msg->exchange->phase == 2
+ && (type < IPSEC_ATTR_SA_LIFE_TYPE
+ || type > IPSEC_ATTR_ECN_TUNNEL)))
+ return -1;
+ return 0;
+}
+
+static int
+ipsec_validate_exchange(u_int8_t exch)
+{
+ return exch != IKE_EXCH_QUICK_MODE && exch != IKE_EXCH_NEW_GROUP_MODE;
+}
+
+static int
+ipsec_validate_id_information(u_int8_t type, u_int8_t *extra, u_int8_t *buf,
+ size_t sz, struct exchange *exchange)
+{
+ u_int8_t proto = GET_IPSEC_ID_PROTO(extra);
+ u_int16_t port = GET_IPSEC_ID_PORT(extra);
+
+ LOG_DBG((LOG_MESSAGE, 40,
+ "ipsec_validate_id_information: proto %d port %d type %d",
+ proto, port, type));
+ if (type < IPSEC_ID_IPV4_ADDR || type > IPSEC_ID_KEY_ID)
+ return -1;
+
+ switch (type) {
+ case IPSEC_ID_IPV4_ADDR:
+ LOG_DBG_BUF((LOG_MESSAGE, 40,
+ "ipsec_validate_id_information: IPv4", buf,
+ sizeof(struct in_addr)));
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ LOG_DBG_BUF((LOG_MESSAGE, 40,
+ "ipsec_validate_id_information: IPv6", buf,
+ sizeof(struct in6_addr)));
+ break;
+
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ LOG_DBG_BUF((LOG_MESSAGE, 40,
+ "ipsec_validate_id_information: IPv4 network/netmask",
+ buf, 2 * sizeof(struct in_addr)));
+ break;
+
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ LOG_DBG_BUF((LOG_MESSAGE, 40,
+ "ipsec_validate_id_information: IPv6 network/netmask",
+ buf, 2 * sizeof(struct in6_addr)));
+ break;
+
+ default:
+ break;
+ }
+
+ if (exchange->phase == 1
+ && (proto != IPPROTO_UDP || port != UDP_DEFAULT_PORT)
+ && (proto != 0 || port != 0)) {
+ /*
+ * XXX SSH's ISAKMP tester fails this test (proto 17 - port
+ * 0).
+ */
+#ifdef notyet
+ return -1;
+#else
+ log_print("ipsec_validate_id_information: dubious ID "
+ "information accepted");
+#endif
+ }
+ /* XXX More checks? */
+
+ return 0;
+}
+
+static int
+ipsec_validate_key_information(u_int8_t *buf, size_t sz)
+{
+ /* XXX Not implemented yet. */
+ return 0;
+}
+
+static int
+ipsec_validate_notification(u_int16_t type)
+{
+ return type < IPSEC_NOTIFY_RESPONDER_LIFETIME
+ || type > IPSEC_NOTIFY_INITIAL_CONTACT ? -1 : 0;
+}
+
+static int
+ipsec_validate_proto(u_int8_t proto)
+{
+ return proto < IPSEC_PROTO_IPSEC_AH
+ || proto > IPSEC_PROTO_IPCOMP ? -1 : 0;
+}
+
+static int
+ipsec_validate_situation(u_int8_t *buf, size_t *sz, size_t len)
+{
+ if (len < IPSEC_SIT_SIT_OFF + IPSEC_SIT_SIT_LEN) {
+ log_print("ipsec_validate_situation: payload too short: %u",
+ (unsigned int) len);
+ return -1;
+ }
+ /* Currently only "identity only" situations are supported. */
+ if (GET_IPSEC_SIT_SIT(buf) != IPSEC_SIT_IDENTITY_ONLY)
+ return 1;
+
+ *sz = IPSEC_SIT_SIT_LEN;
+
+ return 0;
+}
+
+static int
+ipsec_validate_transform_id(u_int8_t proto, u_int8_t transform_id)
+{
+ switch (proto) {
+ /*
+ * As no unexpected protocols can occur, we just tie the
+ * default case to the first case, in orer to silence a GCC
+ * warning.
+ */
+ default:
+ case ISAKMP_PROTO_ISAKMP:
+ return transform_id != IPSEC_TRANSFORM_KEY_IKE;
+ case IPSEC_PROTO_IPSEC_AH:
+ return transform_id < IPSEC_AH_MD5
+ || transform_id > IPSEC_AH_DES ? -1 : 0;
+ case IPSEC_PROTO_IPSEC_ESP:
+ return transform_id < IPSEC_ESP_DES_IV64
+ || (transform_id > IPSEC_ESP_AES_128_CTR
+ && transform_id < IPSEC_ESP_AES_MARS)
+ || transform_id > IPSEC_ESP_AES_TWOFISH ? -1 : 0;
+ case IPSEC_PROTO_IPCOMP:
+ return transform_id < IPSEC_IPCOMP_OUI
+ || transform_id > IPSEC_IPCOMP_V42BIS ? -1 : 0;
+ }
+}
+
+static int
+ipsec_initiator(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ int (**script)(struct message *) = 0;
+
+ /* Check that the SA is coherent with the IKE rules. */
+ if (exchange->type != ISAKMP_EXCH_TRANSACTION
+ && ((exchange->phase == 1 &&
+ exchange->type != ISAKMP_EXCH_ID_PROT &&
+ exchange->type != ISAKMP_EXCH_AGGRESSIVE &&
+ exchange->type != ISAKMP_EXCH_INFO)
+ || (exchange->phase == 2 &&
+ exchange->type != IKE_EXCH_QUICK_MODE &&
+ exchange->type != ISAKMP_EXCH_INFO))) {
+ log_print("ipsec_initiator: unsupported exchange type %d "
+ "in phase %d", exchange->type, exchange->phase);
+ return -1;
+ }
+ switch (exchange->type) {
+ case ISAKMP_EXCH_ID_PROT:
+ script = ike_main_mode_initiator;
+ break;
+#ifdef USE_AGGRESSIVE
+ case ISAKMP_EXCH_AGGRESSIVE:
+ script = ike_aggressive_initiator;
+ break;
+#endif
+#ifdef USE_ISAKMP_CFG
+ case ISAKMP_EXCH_TRANSACTION:
+ script = isakmp_cfg_initiator;
+ break;
+#endif
+ case ISAKMP_EXCH_INFO:
+ return message_send_info(msg);
+ case IKE_EXCH_QUICK_MODE:
+ script = ike_quick_mode_initiator;
+ break;
+ default:
+ log_print("ipsec_initiator: unsupported exchange type %d",
+ exchange->type);
+ return -1;
+ }
+
+ /* Run the script code for this step. */
+ if (script)
+ return script[exchange->step] (msg);
+
+ return 0;
+}
+
+/*
+ * delete all SA's from addr with the associated proto and SPI's
+ *
+ * spis[] is an array of SPIs of size 16-octet for proto ISAKMP
+ * or 4-octet otherwise.
+ */
+static void
+ipsec_delete_spi_list(struct sockaddr *addr, u_int8_t proto, u_int8_t *spis,
+ int nspis, char *type)
+{
+ struct sa *sa;
+ int i;
+
+ for (i = 0; i < nspis; i++) {
+ if (proto == ISAKMP_PROTO_ISAKMP) {
+ u_int8_t *spi = spis + i * ISAKMP_HDR_COOKIES_LEN;
+
+ /*
+ * This really shouldn't happen in IPSEC DOI
+ * code, but Cisco VPN 3000 sends ISAKMP DELETE's
+ * this way.
+ */
+ sa = sa_lookup_isakmp_sa(addr, spi);
+ } else {
+ u_int32_t spi = ((u_int32_t *)spis)[i];
+
+ sa = ipsec_sa_lookup(addr, spi, proto);
+ }
+
+ if (sa == NULL) {
+ LOG_DBG((LOG_SA, 30, "ipsec_delete_spi_list: could "
+ "not locate SA (SPI %08x, proto %u)",
+ ((u_int32_t *)spis)[i], proto));
+ continue;
+ }
+ /* Delete the SA and search for the next */
+ LOG_DBG((LOG_SA, 30, "ipsec_delete_spi_list: "
+ "%s made us delete SA %p (%d references) for proto %d",
+ type, sa, sa->refcnt, proto));
+
+ sa_free(sa);
+ }
+}
+
+/*
+ * deal with a NOTIFY of INVALID_SPI
+ */
+static void
+ipsec_invalid_spi (struct message *msg, struct payload *p)
+{
+ struct sockaddr *dst;
+ int invspisz, off;
+ u_int32_t spi;
+ u_int16_t totsiz;
+ u_int8_t spisz;
+
+ /* Any notification that make us do something should be protected */
+ if(!TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]))
+ {
+ LOG_DBG ((LOG_SA, 40,
+ "ipsec_invalid_spi: missing HASH payload in INVALID_SPI"
+ " notification"));
+ return;
+ }
+
+ /*
+ * get the invalid spi out of the variable sized notification data
+ * field, which is after the variable sized SPI field [which specifies
+ * the receiving entity's phase-1 SPI, not the invalid spi]
+ */
+ totsiz = GET_ISAKMP_GEN_LENGTH (p->p);
+ spisz = GET_ISAKMP_NOTIFY_SPI_SZ (p->p);
+ off = ISAKMP_NOTIFY_SPI_OFF + spisz;
+ invspisz = totsiz - off;
+
+ if (invspisz != sizeof spi)
+ {
+ LOG_DBG ((LOG_SA, 40,
+ "ipsec_invalid_spi: SPI size %d in INVALID_SPI "
+ "payload unsupported", spisz));
+ return;
+ }
+ memcpy (&spi, p->p + off, sizeof spi);
+
+ msg->transport->vtbl->get_dst (msg->transport, &dst);
+
+ /* delete matching SPI's from this peer */
+ ipsec_delete_spi_list (dst, 0, (u_int8_t *)&spi, 1, "INVALID_SPI");
+}
+
+static int
+ipsec_responder(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ int (**script)(struct message *) = 0;
+ struct payload *p;
+ u_int16_t type;
+
+ /* Check that a new exchange is coherent with the IKE rules. */
+ if (exchange->step == 0 && exchange->type != ISAKMP_EXCH_TRANSACTION
+ && ((exchange->phase == 1 &&
+ exchange->type != ISAKMP_EXCH_ID_PROT &&
+ exchange->type != ISAKMP_EXCH_AGGRESSIVE &&
+ exchange->type != ISAKMP_EXCH_INFO)
+ || (exchange->phase == 2 &&
+ exchange->type != IKE_EXCH_QUICK_MODE &&
+ exchange->type != ISAKMP_EXCH_INFO))) {
+ message_drop(msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE,
+ 0, 1, 0);
+ return -1;
+ }
+ LOG_DBG((LOG_MISC, 30, "ipsec_responder: phase %d exchange %d step %d",
+ exchange->phase, exchange->type, exchange->step));
+ switch (exchange->type) {
+ case ISAKMP_EXCH_ID_PROT:
+ script = ike_main_mode_responder;
+ break;
+#ifdef USE_AGGRESSIVE
+ case ISAKMP_EXCH_AGGRESSIVE:
+ script = ike_aggressive_responder;
+ break;
+#endif
+#ifdef USE_ISAKMP_CFG
+ case ISAKMP_EXCH_TRANSACTION:
+ script = isakmp_cfg_responder;
+ break;
+#endif
+ case ISAKMP_EXCH_INFO:
+ for (p = payload_first(msg, ISAKMP_PAYLOAD_NOTIFY); p;
+ p = TAILQ_NEXT(p, link)) {
+ type = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p);
+ LOG_DBG((LOG_EXCHANGE, 10,
+ "ipsec_responder: got NOTIFY of type %s",
+ constant_name(isakmp_notify_cst, type)));
+
+ switch (type) {
+ case IPSEC_NOTIFY_INITIAL_CONTACT:
+ /* Handled by leftover logic. */
+ break;
+
+#if defined (USE_DPD)
+ case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE:
+ case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK:
+ dpd_handle_notify(msg, p);
+ break;
+#endif
+
+ default:
+ p->flags |= PL_MARK;
+ break;
+ }
+ }
+
+ /*
+ * If any DELETEs are in here, let the logic of leftover
+ * payloads deal with them.
+ */
+ return 0;
+
+ case IKE_EXCH_QUICK_MODE:
+ script = ike_quick_mode_responder;
+ break;
+
+ default:
+ message_drop(msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE,
+ 0, 1, 0);
+ return -1;
+ }
+
+ /* Run the script code for this step. */
+ if (script)
+ return script[exchange->step] (msg);
+
+ /*
+ * XXX So far we don't accept any proposals for exchanges we don't
+ * support.
+ */
+ if (payload_first(msg, ISAKMP_PAYLOAD_SA)) {
+ message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);
+ return -1;
+ }
+ return 0;
+}
+
+static enum hashes
+from_ike_hash(u_int16_t hash)
+{
+ switch (hash) {
+ case IKE_HASH_MD5:
+ return HASH_MD5;
+ case IKE_HASH_SHA:
+ return HASH_SHA1;
+ }
+ return -1;
+}
+
+static enum transform
+from_ike_crypto(u_int16_t crypto)
+{
+ /* Coincidentally this is the null operation :-) */
+ return crypto;
+}
+
+/*
+ * Find out whether the attribute of type TYPE with a LEN length value
+ * pointed to by VALUE is incompatible with what we can handle.
+ * VMSG is a pointer to the current message.
+ */
+int
+ipsec_is_attribute_incompatible(u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vmsg)
+{
+ struct message *msg = vmsg;
+ u_int16_t dv = decode_16(value);
+
+ if (msg->exchange->phase == 1) {
+ switch (type) {
+ case IKE_ATTR_ENCRYPTION_ALGORITHM:
+ return !crypto_get(from_ike_crypto(dv));
+ case IKE_ATTR_HASH_ALGORITHM:
+ return !hash_get(from_ike_hash(dv));
+ case IKE_ATTR_AUTHENTICATION_METHOD:
+ return !ike_auth_get(dv);
+ case IKE_ATTR_GROUP_DESCRIPTION:
+ return (dv < IKE_GROUP_DESC_MODP_768
+ || dv > IKE_GROUP_DESC_MODP_1536)
+ && (dv < IKE_GROUP_DESC_MODP_2048
+ || dv > IKE_GROUP_DESC_MODP_8192);
+ case IKE_ATTR_GROUP_TYPE:
+ return 1;
+ case IKE_ATTR_GROUP_PRIME:
+ return 1;
+ case IKE_ATTR_GROUP_GENERATOR_1:
+ return 1;
+ case IKE_ATTR_GROUP_GENERATOR_2:
+ return 1;
+ case IKE_ATTR_GROUP_CURVE_A:
+ return 1;
+ case IKE_ATTR_GROUP_CURVE_B:
+ return 1;
+ case IKE_ATTR_LIFE_TYPE:
+ return dv < IKE_DURATION_SECONDS
+ || dv > IKE_DURATION_KILOBYTES;
+ case IKE_ATTR_LIFE_DURATION:
+ return len != 2 && len != 4;
+ case IKE_ATTR_PRF:
+ return 1;
+ case IKE_ATTR_KEY_LENGTH:
+ /*
+ * Our crypto routines only allows key-lengths which
+ * are multiples of an octet.
+ */
+ return dv % 8 != 0;
+ case IKE_ATTR_FIELD_SIZE:
+ return 1;
+ case IKE_ATTR_GROUP_ORDER:
+ return 1;
+ }
+ } else {
+ switch (type) {
+ case IPSEC_ATTR_SA_LIFE_TYPE:
+ return dv < IPSEC_DURATION_SECONDS
+ || dv > IPSEC_DURATION_KILOBYTES;
+ case IPSEC_ATTR_SA_LIFE_DURATION:
+ return len != 2 && len != 4;
+ case IPSEC_ATTR_GROUP_DESCRIPTION:
+ return (dv < IKE_GROUP_DESC_MODP_768
+ || dv > IKE_GROUP_DESC_MODP_1536)
+ && (dv < IKE_GROUP_DESC_MODP_2048
+ || IKE_GROUP_DESC_MODP_8192 < dv);
+ case IPSEC_ATTR_ENCAPSULATION_MODE:
+#if defined (USE_NAT_TRAVERSAL)
+ return dv != IPSEC_ENCAP_TUNNEL
+ && dv != IPSEC_ENCAP_TRANSPORT
+ && dv != IPSEC_ENCAP_UDP_ENCAP_TUNNEL
+ && dv != IPSEC_ENCAP_UDP_ENCAP_TRANSPORT
+ && dv != IPSEC_ENCAP_UDP_ENCAP_TUNNEL_DRAFT
+ && dv != IPSEC_ENCAP_UDP_ENCAP_TRANSPORT_DRAFT;
+#else
+ return dv < IPSEC_ENCAP_TUNNEL
+ || dv > IPSEC_ENCAP_TRANSPORT;
+#endif /* USE_NAT_TRAVERSAL */
+ case IPSEC_ATTR_AUTHENTICATION_ALGORITHM:
+ return dv < IPSEC_AUTH_HMAC_MD5
+ || dv > IPSEC_AUTH_HMAC_RIPEMD;
+ case IPSEC_ATTR_KEY_LENGTH:
+ /*
+ * XXX Blowfish needs '0'. Others appear to disregard
+ * this attr?
+ */
+ return 0;
+ case IPSEC_ATTR_KEY_ROUNDS:
+ return 1;
+ case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE:
+ return 1;
+ case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM:
+ return 1;
+ case IPSEC_ATTR_ECN_TUNNEL:
+ return 1;
+ }
+ }
+ /* XXX Silence gcc. */
+ return 1;
+}
+
+#ifdef USE_DEBUG
+/*
+ * Log the attribute of TYPE with a LEN length value pointed to by VALUE
+ * in human-readable form. VMSG is a pointer to the current message.
+ */
+int
+ipsec_debug_attribute(u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vmsg)
+{
+ struct message *msg = vmsg;
+ char val[20];
+
+ /* XXX Transient solution. */
+ if (len == 2)
+ snprintf(val, sizeof val, "%d", decode_16(value));
+ else if (len == 4)
+ snprintf(val, sizeof val, "%d", decode_32(value));
+ else
+ snprintf(val, sizeof val, "unrepresentable");
+
+ LOG_DBG((LOG_MESSAGE, 50, "Attribute %s value %s",
+ constant_name(msg->exchange->phase == 1 ? ike_attr_cst :
+ ipsec_attr_cst, type), val));
+ return 0;
+}
+#endif
+
+/*
+ * Decode the attribute of type TYPE with a LEN length value pointed to by
+ * VALUE. VIDA is a pointer to a context structure where we can find the
+ * current message, SA and protocol.
+ */
+int
+ipsec_decode_attribute(u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vida)
+{
+ struct ipsec_decode_arg *ida = vida;
+ struct message *msg = ida->msg;
+ struct sa *sa = ida->sa;
+ struct ipsec_sa *isa = sa->data;
+ struct proto *proto = ida->proto;
+ struct ipsec_proto *iproto = proto->data;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ static int lifetype = 0;
+
+ if (exchange->phase == 1) {
+ switch (type) {
+ case IKE_ATTR_ENCRYPTION_ALGORITHM:
+ /* XXX Errors possible? */
+ exchange->crypto = crypto_get(from_ike_crypto(
+ decode_16(value)));
+ break;
+ case IKE_ATTR_HASH_ALGORITHM:
+ /* XXX Errors possible? */
+ ie->hash = hash_get(from_ike_hash(decode_16(value)));
+ break;
+ case IKE_ATTR_AUTHENTICATION_METHOD:
+ /* XXX Errors possible? */
+ ie->ike_auth = ike_auth_get(decode_16(value));
+ break;
+ case IKE_ATTR_GROUP_DESCRIPTION:
+ isa->group_desc = decode_16(value);
+ break;
+ case IKE_ATTR_GROUP_TYPE:
+ break;
+ case IKE_ATTR_GROUP_PRIME:
+ break;
+ case IKE_ATTR_GROUP_GENERATOR_1:
+ break;
+ case IKE_ATTR_GROUP_GENERATOR_2:
+ break;
+ case IKE_ATTR_GROUP_CURVE_A:
+ break;
+ case IKE_ATTR_GROUP_CURVE_B:
+ break;
+ case IKE_ATTR_LIFE_TYPE:
+ lifetype = decode_16(value);
+ return 0;
+ case IKE_ATTR_LIFE_DURATION:
+ switch (lifetype) {
+ case IKE_DURATION_SECONDS:
+ switch (len) {
+ case 2:
+ sa->seconds = decode_16(value);
+ break;
+ case 4:
+ sa->seconds = decode_32(value);
+ break;
+ default:
+ log_print("ipsec_decode_attribute: "
+ "unreasonable lifetime");
+ }
+ break;
+ case IKE_DURATION_KILOBYTES:
+ switch (len) {
+ case 2:
+ sa->kilobytes = decode_16(value);
+ break;
+ case 4:
+ sa->kilobytes = decode_32(value);
+ break;
+ default:
+ log_print("ipsec_decode_attribute: "
+ "unreasonable lifetime");
+ }
+ break;
+ default:
+ log_print("ipsec_decode_attribute: unknown "
+ "lifetime type");
+ }
+ break;
+ case IKE_ATTR_PRF:
+ break;
+ case IKE_ATTR_KEY_LENGTH:
+ exchange->key_length = decode_16(value) / 8;
+ break;
+ case IKE_ATTR_FIELD_SIZE:
+ break;
+ case IKE_ATTR_GROUP_ORDER:
+ break;
+ }
+ } else {
+ switch (type) {
+ case IPSEC_ATTR_SA_LIFE_TYPE:
+ lifetype = decode_16(value);
+ return 0;
+ case IPSEC_ATTR_SA_LIFE_DURATION:
+ switch (lifetype) {
+ case IPSEC_DURATION_SECONDS:
+ switch (len) {
+ case 2:
+ sa->seconds = decode_16(value);
+ break;
+ case 4:
+ sa->seconds = decode_32(value);
+ break;
+ default:
+ log_print("ipsec_decode_attribute: "
+ "unreasonable lifetime");
+ }
+ break;
+ case IPSEC_DURATION_KILOBYTES:
+ switch (len) {
+ case 2:
+ sa->kilobytes = decode_16(value);
+ break;
+ case 4:
+ sa->kilobytes = decode_32(value);
+ break;
+ default:
+ log_print("ipsec_decode_attribute: "
+ "unreasonable lifetime");
+ }
+ break;
+ default:
+ log_print("ipsec_decode_attribute: unknown "
+ "lifetime type");
+ }
+ break;
+ case IPSEC_ATTR_GROUP_DESCRIPTION:
+ isa->group_desc = decode_16(value);
+ break;
+ case IPSEC_ATTR_ENCAPSULATION_MODE:
+ /*
+ * XXX Multiple protocols must have same
+ * encapsulation mode, no?
+ */
+ iproto->encap_mode = decode_16(value);
+ break;
+ case IPSEC_ATTR_AUTHENTICATION_ALGORITHM:
+ iproto->auth = decode_16(value);
+ break;
+ case IPSEC_ATTR_KEY_LENGTH:
+ iproto->keylen = decode_16(value);
+ break;
+ case IPSEC_ATTR_KEY_ROUNDS:
+ iproto->keyrounds = decode_16(value);
+ break;
+ case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE:
+ break;
+ case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM:
+ break;
+ case IPSEC_ATTR_ECN_TUNNEL:
+ break;
+ }
+ }
+ lifetype = 0;
+ return 0;
+}
+
+/*
+ * Walk over the attributes of the transform payload found in BUF, and
+ * fill out the fields of the SA attached to MSG. Also mark the SA as
+ * processed.
+ */
+void
+ipsec_decode_transform(struct message *msg, struct sa *sa, struct proto *proto,
+ u_int8_t *buf)
+{
+ struct ipsec_exch *ie = msg->exchange->data;
+ struct ipsec_decode_arg ida;
+
+ LOG_DBG((LOG_MISC, 20, "ipsec_decode_transform: transform %d chosen",
+ GET_ISAKMP_TRANSFORM_NO(buf)));
+
+ ida.msg = msg;
+ ida.sa = sa;
+ ida.proto = proto;
+
+ /* The default IKE lifetime is 8 hours. */
+ if (sa->phase == 1)
+ sa->seconds = 28800;
+
+ /* Extract the attributes and stuff them into the SA. */
+ attribute_map(buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH(buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ ipsec_decode_attribute, &ida);
+
+ /*
+ * If no pseudo-random function was negotiated, it's HMAC.
+ * XXX As PRF_HMAC currently is zero, this is a no-op.
+ */
+ if (!ie->prf_type)
+ ie->prf_type = PRF_HMAC;
+}
+
+/*
+ * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO
+ * of the IKE security association SA.
+ */
+static void
+ipsec_delete_spi(struct sa *sa, struct proto *proto, int incoming)
+{
+ if (sa->phase == 1)
+ return;
+ /* XXX Error handling? Is it interesting? */
+ sysdep_ipsec_delete_spi(sa, proto, incoming);
+}
+
+/*
+ * Store BUF into the g^x entry of the exchange that message MSG belongs to.
+ * PEER is non-zero when the value is our peer's, and zero when it is ours.
+ */
+static int
+ipsec_g_x(struct message *msg, int peer, u_int8_t *buf)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t **g_x;
+ int initiator = exchange->initiator ^ peer;
+ char header[32];
+
+ g_x = initiator ? &ie->g_xi : &ie->g_xr;
+ *g_x = malloc(ie->g_x_len);
+ if (!*g_x) {
+ log_error("ipsec_g_x: malloc (%lu) failed",
+ (unsigned long)ie->g_x_len);
+ return -1;
+ }
+ memcpy(*g_x, buf, ie->g_x_len);
+ snprintf(header, sizeof header, "ipsec_g_x: g^x%c",
+ initiator ? 'i' : 'r');
+ LOG_DBG_BUF((LOG_MISC, 80, header, *g_x, ie->g_x_len));
+ return 0;
+}
+
+/* Generate our DH value. */
+int
+ipsec_gen_g_x(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t *buf;
+
+ buf = malloc(ISAKMP_KE_SZ + ie->g_x_len);
+ if (!buf) {
+ log_error("ipsec_gen_g_x: malloc (%lu) failed",
+ ISAKMP_KE_SZ + (unsigned long)ie->g_x_len);
+ return -1;
+ }
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_KEY_EXCH, buf,
+ ISAKMP_KE_SZ + ie->g_x_len, 1)) {
+ free(buf);
+ return -1;
+ }
+ if (dh_create_exchange(ie->group, buf + ISAKMP_KE_DATA_OFF)) {
+ log_print("ipsec_gen_g_x: dh_create_exchange failed");
+ free(buf);
+ return -1;
+ }
+ return ipsec_g_x(msg, 0, buf + ISAKMP_KE_DATA_OFF);
+}
+
+/* Save the peer's DH value. */
+int
+ipsec_save_g_x(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct payload *kep;
+
+ kep = payload_first(msg, ISAKMP_PAYLOAD_KEY_EXCH);
+ kep->flags |= PL_MARK;
+ ie->g_x_len = GET_ISAKMP_GEN_LENGTH(kep->p) - ISAKMP_KE_DATA_OFF;
+
+ /* Check that the given length matches the group's expectancy. */
+ if (ie->g_x_len != (size_t) dh_getlen(ie->group)) {
+ /* XXX Is this a good notify type? */
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
+ return -1;
+ }
+ return ipsec_g_x(msg, 1, kep->p + ISAKMP_KE_DATA_OFF);
+}
+
+/*
+ * Get a SPI for PROTO and the transport MSG passed over. Store the
+ * size where SZ points. NB! A zero return is OK if *SZ is zero.
+ */
+static u_int8_t *
+ipsec_get_spi(size_t *sz, u_int8_t proto, struct message *msg)
+{
+ struct sockaddr *dst, *src;
+ struct transport *transport = msg->transport;
+
+ if (msg->exchange->phase == 1) {
+ *sz = 0;
+ return 0;
+ } else {
+ /* We are the destination in the SA we want a SPI for. */
+ transport->vtbl->get_src(transport, &dst);
+ /* The peer is the source. */
+ transport->vtbl->get_dst(transport, &src);
+ return sysdep_ipsec_get_spi(sz, proto, src, dst,
+ msg->exchange->seq);
+ }
+}
+
+/*
+ * We have gotten a payload PAYLOAD of type TYPE, which did not get handled
+ * by the logic of the exchange MSG takes part in. Now is the time to deal
+ * with such a payload if we know how to, if we don't, return -1, otherwise
+ * 0.
+ */
+int
+ipsec_handle_leftover_payload(struct message *msg, u_int8_t type,
+ struct payload *payload)
+{
+ u_int32_t spisz, nspis;
+ struct sockaddr *dst;
+ int reenter = 0;
+ u_int8_t *spis, proto;
+ struct sa *sa;
+
+ switch (type) {
+ case ISAKMP_PAYLOAD_DELETE:
+ proto = GET_ISAKMP_DELETE_PROTO(payload->p);
+ nspis = GET_ISAKMP_DELETE_NSPIS(payload->p);
+ spisz = GET_ISAKMP_DELETE_SPI_SZ(payload->p);
+
+ if (nspis == 0) {
+ LOG_DBG((LOG_SA, 60, "ipsec_handle_leftover_payload: "
+ "message specified zero SPIs, ignoring"));
+ return -1;
+ }
+ /* verify proper SPI size */
+ if ((proto == ISAKMP_PROTO_ISAKMP && spisz !=
+ ISAKMP_HDR_COOKIES_LEN)
+ || (proto != ISAKMP_PROTO_ISAKMP && spisz !=
+ sizeof(u_int32_t))) {
+ log_print("ipsec_handle_leftover_payload: invalid SPI "
+ "size %d for proto %d in DELETE payload",
+ spisz, proto);
+ return -1;
+ }
+ spis = (u_int8_t *) malloc(nspis * spisz);
+ if (!spis) {
+ log_error("ipsec_handle_leftover_payload: malloc "
+ "(%d) failed", nspis * spisz);
+ return -1;
+ }
+ /* extract SPI and get dst address */
+ memcpy(spis, payload->p + ISAKMP_DELETE_SPI_OFF, nspis * spisz);
+ msg->transport->vtbl->get_dst(msg->transport, &dst);
+
+ ipsec_delete_spi_list(dst, proto, spis, nspis, "DELETE");
+
+ free(spis);
+ payload->flags |= PL_MARK;
+ return 0;
+
+ case ISAKMP_PAYLOAD_NOTIFY:
+ switch (GET_ISAKMP_NOTIFY_MSG_TYPE(payload->p)) {
+ case IPSEC_NOTIFY_INITIAL_CONTACT:
+ /*
+ * Permit INITIAL-CONTACT if
+ * - this is not an AGGRESSIVE mode exchange
+ * - it is protected by an ISAKMP SA
+ *
+ * XXX Instead of the first condition above, we could
+ * XXX permit this only for phase 2. In the last
+ * XXX packet of main-mode, this payload, while
+ * XXX encrypted, is not part of the hash digest. As
+ * XXX we currently send our own INITIAL-CONTACTs at
+ * XXX this point, this too would need to be changed.
+ */
+ if (msg->exchange->type == ISAKMP_EXCH_AGGRESSIVE) {
+ log_print("ipsec_handle_leftover_payload: got "
+ "INITIAL-CONTACT in AGGRESSIVE mode");
+ return -1;
+ }
+ if ((msg->exchange->flags & EXCHANGE_FLAG_ENCRYPT)
+ == 0) {
+ log_print("ipsec_handle_leftover_payload: got "
+ "INITIAL-CONTACT without ISAKMP SA");
+ return -1;
+ }
+
+ if ((msg->flags & MSG_AUTHENTICATED) == 0) {
+ log_print("ipsec_handle_leftover_payload: "
+ "got unauthenticated INITIAL-CONTACT");
+ return -1;
+ }
+ /*
+ * Find out who is sending this and then delete every
+ * SA that is ready. Exchanges will timeout
+ * themselves and then the non-ready SAs will
+ * disappear too.
+ */
+ msg->transport->vtbl->get_dst(msg->transport, &dst);
+ while ((sa = sa_lookup_by_peer(dst,
+ sysdep_sa_len(dst))) != 0) {
+ /*
+ * Don't delete the current SA -- we received
+ * the notification over it, so it's obviously
+ * still active. We temporarily need to remove
+ * the SA from the list to avoid an endless
+ * loop, but keep a reference so it won't
+ * disappear meanwhile.
+ */
+ if (sa == msg->isakmp_sa) {
+ sa_reference(sa);
+ sa_remove(sa);
+ reenter = 1;
+ continue;
+ }
+ LOG_DBG((LOG_SA, 30,
+ "ipsec_handle_leftover_payload: "
+ "INITIAL-CONTACT made us delete SA %p",
+ sa));
+ sa_delete(sa, 0);
+ }
+
+ if (reenter) {
+ sa_enter(msg->isakmp_sa);
+ sa_release(msg->isakmp_sa);
+ }
+ payload->flags |= PL_MARK;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/* Return the encryption keylength in octets of the ESP protocol PROTO. */
+int
+ipsec_esp_enckeylength(struct proto *proto)
+{
+ struct ipsec_proto *iproto = proto->data;
+
+ /* Compute the keylength to use. */
+ switch (proto->id) {
+ case IPSEC_ESP_DES:
+ case IPSEC_ESP_DES_IV32:
+ case IPSEC_ESP_DES_IV64:
+ return 8;
+ case IPSEC_ESP_3DES:
+ return 24;
+ case IPSEC_ESP_CAST:
+ if (!iproto->keylen)
+ return 16;
+ return iproto->keylen / 8;
+ case IPSEC_ESP_AES:
+ case IPSEC_ESP_AES_128_CTR:
+ if (!iproto->keylen)
+ return 16;
+ /* Fallthrough */
+ default:
+ return iproto->keylen / 8;
+ }
+}
+
+/* Return the authentication keylength in octets of the ESP protocol PROTO. */
+int
+ipsec_esp_authkeylength(struct proto *proto)
+{
+ struct ipsec_proto *iproto = proto->data;
+
+ switch (iproto->auth) {
+ case IPSEC_AUTH_HMAC_MD5:
+ return 16;
+ case IPSEC_AUTH_HMAC_SHA:
+ case IPSEC_AUTH_HMAC_RIPEMD:
+ return 20;
+ case IPSEC_AUTH_HMAC_SHA2_256:
+ return 32;
+ case IPSEC_AUTH_HMAC_SHA2_384:
+ return 48;
+ case IPSEC_AUTH_HMAC_SHA2_512:
+ return 64;
+ default:
+ return 0;
+ }
+}
+
+/* Return the authentication keylength in octets of the AH protocol PROTO. */
+int
+ipsec_ah_keylength(struct proto *proto)
+{
+ switch (proto->id) {
+ case IPSEC_AH_MD5:
+ return 16;
+ case IPSEC_AH_SHA:
+ case IPSEC_AH_RIPEMD:
+ return 20;
+ case IPSEC_AH_SHA2_256:
+ return 32;
+ case IPSEC_AH_SHA2_384:
+ return 48;
+ case IPSEC_AH_SHA2_512:
+ return 64;
+ default:
+ return -1;
+ }
+}
+
+/* Return the total keymaterial length of the protocol PROTO. */
+int
+ipsec_keymat_length(struct proto *proto)
+{
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ return ipsec_esp_enckeylength(proto)
+ + ipsec_esp_authkeylength(proto);
+ case IPSEC_PROTO_IPSEC_AH:
+ return ipsec_ah_keylength(proto);
+ default:
+ return -1;
+ }
+}
+
+/* Helper function for ipsec_get_id(). */
+static int
+ipsec_get_proto_port(char *section, u_int8_t *tproto, u_int16_t *port)
+{
+ struct protoent *pe = NULL;
+ struct servent *se;
+ char *pstr;
+
+ pstr = conf_get_str(section, "Protocol");
+ if (!pstr) {
+ *tproto = 0;
+ return 0;
+ }
+ *tproto = (u_int8_t)atoi(pstr);
+ if (!*tproto) {
+ pe = getprotobyname(pstr);
+ if (pe)
+ *tproto = pe->p_proto;
+ }
+ if (!*tproto) {
+ log_print("ipsec_get_proto_port: protocol \"%s\" unknown",
+ pstr);
+ return -1;
+ }
+
+ pstr = conf_get_str(section, "Port");
+ if (!pstr)
+ return 0;
+ *port = (u_int16_t)atoi(pstr);
+ if (!*port) {
+ se = getservbyname(pstr,
+ pe ? pe->p_name : (pstr ? pstr : NULL));
+ if (se)
+ *port = se->s_port;
+ }
+ if (!*port) {
+ log_print("ipsec_get_proto_port: port \"%s\" unknown",
+ pstr);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Out of a named section SECTION in the configuration file find out
+ * the network address and mask as well as the ID type. Put the info
+ * in the areas pointed to by ADDR, MASK, TPROTO, PORT, and ID respectively.
+ * Return 0 on success and -1 on failure.
+ */
+int
+ipsec_get_id(char *section, int *id, struct sockaddr **addr,
+ struct sockaddr **mask, u_int8_t *tproto, u_int16_t *port)
+{
+ char *type, *address, *netmask;
+
+ type = conf_get_str(section, "ID-type");
+ if (!type) {
+ log_print("ipsec_get_id: section %s has no \"ID-type\" tag",
+ section);
+ return -1;
+ }
+ *id = constant_value(ipsec_id_cst, type);
+ switch (*id) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV6_ADDR: {
+ int ret;
+
+ address = conf_get_str(section, "Address");
+ if (!address) {
+ log_print("ipsec_get_id: section %s has no "
+ "\"Address\" tag", section);
+ return -1;
+ }
+ if (text2sockaddr(address, NULL, addr)) {
+ log_print("ipsec_get_id: invalid address %s in "
+ "section %s", address, section);
+ return -1;
+ }
+ ret = ipsec_get_proto_port(section, tproto, port);
+ if (ret < 0)
+ free(*addr);
+
+ return ret;
+ }
+
+#ifdef notyet
+ case IPSEC_ID_FQDN:
+ return -1;
+
+ case IPSEC_ID_USER_FQDN:
+ return -1;
+#endif
+
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ case IPSEC_ID_IPV6_ADDR_SUBNET: {
+ int ret;
+
+ address = conf_get_str(section, "Network");
+ if (!address) {
+ log_print("ipsec_get_id: section %s has no "
+ "\"Network\" tag", section);
+ return -1;
+ }
+ if (text2sockaddr(address, NULL, addr)) {
+ log_print("ipsec_get_id: invalid section %s "
+ "network %s", section, address);
+ return -1;
+ }
+ netmask = conf_get_str(section, "Netmask");
+ if (!netmask) {
+ log_print("ipsec_get_id: section %s has no "
+ "\"Netmask\" tag", section);
+ free(*addr);
+ return -1;
+ }
+ if (text2sockaddr(netmask, NULL, mask)) {
+ log_print("ipsec_id_build: invalid section %s "
+ "network %s", section, netmask);
+ free(*addr);
+ return -1;
+ }
+ ret = ipsec_get_proto_port(section, tproto, port);
+ if (ret < 0) {
+ free(*mask);
+ free(*addr);
+ }
+ return ret;
+ }
+
+#ifdef notyet
+ case IPSEC_ID_IPV4_RANGE:
+ return -1;
+
+ case IPSEC_ID_IPV6_RANGE:
+ return -1;
+
+ case IPSEC_ID_DER_ASN1_DN:
+ return -1;
+
+ case IPSEC_ID_DER_ASN1_GN:
+ return -1;
+
+ case IPSEC_ID_KEY_ID:
+ return -1;
+#endif
+
+ default:
+ log_print("ipsec_get_id: unknown ID type \"%s\" in "
+ "section %s", type, section);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * XXX I rather want this function to return a status code, and fail if
+ * we cannot fit the information in the supplied buffer.
+ */
+static void
+ipsec_decode_id(char *buf, size_t size, u_int8_t *id, size_t id_len,
+ int isakmpform)
+{
+ int id_type;
+ char *addr = 0, *mask = 0;
+ u_int32_t *idp;
+
+ if (id) {
+ if (!isakmpform) {
+ /*
+ * Exchanges and SAs dont carry the IDs in ISAKMP
+ * form.
+ */
+ id -= ISAKMP_GEN_SZ;
+ id_len += ISAKMP_GEN_SZ;
+ }
+ id_type = GET_ISAKMP_ID_TYPE(id);
+ idp = (u_int32_t *) (id + ISAKMP_ID_DATA_OFF);
+ switch (id_type) {
+ case IPSEC_ID_IPV4_ADDR:
+ util_ntoa(&addr, AF_INET, id + ISAKMP_ID_DATA_OFF);
+ snprintf(buf, size, "%08x: %s",
+ decode_32(id + ISAKMP_ID_DATA_OFF), addr);
+ break;
+
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ util_ntoa(&addr, AF_INET, id + ISAKMP_ID_DATA_OFF);
+ util_ntoa(&mask, AF_INET, id + ISAKMP_ID_DATA_OFF + 4);
+ snprintf(buf, size, "%08x/%08x: %s/%s",
+ decode_32(id + ISAKMP_ID_DATA_OFF),
+ decode_32(id + ISAKMP_ID_DATA_OFF + 4), addr, mask);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF);
+ snprintf(buf, size, "%08x%08x%08x%08x: %s", *idp,
+ *(idp + 1), *(idp + 2), *(idp + 3), addr);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF);
+ util_ntoa(&mask, AF_INET6, id + ISAKMP_ID_DATA_OFF +
+ sizeof(struct in6_addr));
+ snprintf(buf, size,
+ "%08x%08x%08x%08x/%08x%08x%08x%08x: %s/%s", *idp,
+ *(idp + 1), *(idp + 2), *(idp + 3), *(idp + 4),
+ *(idp + 5), *(idp + 6), *(idp + 7), addr, mask);
+ break;
+
+ case IPSEC_ID_FQDN:
+ case IPSEC_ID_USER_FQDN:
+ /* String is not NUL terminated, be careful */
+ id_len -= ISAKMP_ID_DATA_OFF;
+ id_len = MIN(id_len, size - 1);
+ memcpy(buf, id + ISAKMP_ID_DATA_OFF, id_len);
+ buf[id_len] = '\0';
+ break;
+
+#ifdef USE_X509
+ case IPSEC_ID_DER_ASN1_DN:
+ addr = x509_DN_string(id + ISAKMP_ID_DATA_OFF,
+ id_len - ISAKMP_ID_DATA_OFF);
+ if (!addr) {
+ snprintf(buf, size, "unparsable ASN1 DN ID");
+ return;
+ }
+ strlcpy(buf, addr, size);
+ break;
+#endif
+
+ default:
+ snprintf(buf, size, "<id type unknown: %x>", id_type);
+ break;
+ }
+ } else
+ snprintf(buf, size, "<no ipsec id>");
+ if (addr)
+ free(addr);
+ if (mask)
+ free(mask);
+}
+
+char *
+ipsec_decode_ids(char *fmt, u_int8_t *id1, size_t id1_len, u_int8_t *id2,
+ size_t id2_len, int isakmpform)
+{
+ static char result[1024];
+ char s_id1[256], s_id2[256];
+
+ ipsec_decode_id(s_id1, sizeof s_id1, id1, id1_len, isakmpform);
+ ipsec_decode_id(s_id2, sizeof s_id2, id2, id2_len, isakmpform);
+
+ snprintf(result, sizeof result, fmt, s_id1, s_id2);
+ return result;
+}
+
+/*
+ * Out of a named section SECTION in the configuration file build an
+ * ISAKMP ID payload. Ths payload size should be stashed in SZ.
+ * The caller is responsible for freeing the payload.
+ */
+u_int8_t *
+ipsec_build_id(char *section, size_t *sz)
+{
+ struct sockaddr *addr, *mask;
+ u_int8_t *p;
+ int id, subnet = 0;
+ u_int8_t tproto = 0;
+ u_int16_t port = 0;
+
+ if (ipsec_get_id(section, &id, &addr, &mask, &tproto, &port))
+ return 0;
+
+ if (id == IPSEC_ID_IPV4_ADDR_SUBNET || id == IPSEC_ID_IPV6_ADDR_SUBNET)
+ subnet = 1;
+
+ *sz = ISAKMP_ID_SZ + sockaddr_addrlen(addr);
+ if (subnet)
+ *sz += sockaddr_addrlen(mask);
+
+ p = malloc(*sz);
+ if (!p) {
+ log_print("ipsec_build_id: malloc(%lu) failed",
+ (unsigned long)*sz);
+ if (subnet)
+ free(mask);
+ free(addr);
+ return 0;
+ }
+ SET_ISAKMP_ID_TYPE(p, id);
+ SET_ISAKMP_ID_DOI_DATA(p, (unsigned char *)"\000\000\000");
+
+ memcpy(p + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(addr),
+ sockaddr_addrlen(addr));
+ if (subnet)
+ memcpy(p + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(addr),
+ sockaddr_addrdata(mask), sockaddr_addrlen(mask));
+
+ SET_IPSEC_ID_PROTO(p + ISAKMP_ID_DOI_DATA_OFF, tproto);
+ SET_IPSEC_ID_PORT(p + ISAKMP_ID_DOI_DATA_OFF, port);
+
+ if (subnet)
+ free(mask);
+ free(addr);
+ return p;
+}
+
+/*
+ * copy an ISAKMPD id
+ */
+int
+ipsec_clone_id(u_int8_t **did, size_t *did_len, u_int8_t *id, size_t id_len)
+{
+ if (*did)
+ free(*did);
+
+ if (!id_len || !id) {
+ *did = 0;
+ *did_len = 0;
+ return 0;
+ }
+ *did = malloc(id_len);
+ if (!*did) {
+ *did_len = 0;
+ log_error("ipsec_clone_id: malloc(%lu) failed",
+ (unsigned long)id_len);
+ return -1;
+ }
+ *did_len = id_len;
+ memcpy(*did, id, id_len);
+
+ return 0;
+}
+
+/*
+ * IPsec-specific PROTO initializations. SECTION is only set if we are the
+ * initiator thus only usable there.
+ * XXX I want to fix this later.
+ */
+void
+ipsec_proto_init(struct proto *proto, char *section)
+{
+ struct ipsec_proto *iproto = proto->data;
+
+ if (proto->sa->phase == 2)
+ iproto->replay_window = section ? conf_get_num(section,
+ "ReplayWindow", DEFAULT_REPLAY_WINDOW) :
+ DEFAULT_REPLAY_WINDOW;
+}
+
+/*
+ * Add a notification payload of type INITIAL CONTACT to MSG if this is
+ * the first contact we have made to our peer.
+ */
+int
+ipsec_initial_contact(struct message *msg)
+{
+ u_int8_t *buf;
+
+ if (ipsec_contacted(msg))
+ return 0;
+
+ buf = malloc(ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN);
+ if (!buf) {
+ log_error("ike_phase_1_initial_contact: malloc (%d) failed",
+ ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN);
+ return -1;
+ }
+ SET_ISAKMP_NOTIFY_DOI(buf, IPSEC_DOI_IPSEC);
+ SET_ISAKMP_NOTIFY_PROTO(buf, ISAKMP_PROTO_ISAKMP);
+ SET_ISAKMP_NOTIFY_SPI_SZ(buf, ISAKMP_HDR_COOKIES_LEN);
+ SET_ISAKMP_NOTIFY_MSG_TYPE(buf, IPSEC_NOTIFY_INITIAL_CONTACT);
+ memcpy(buf + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies,
+ ISAKMP_HDR_COOKIES_LEN);
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_NOTIFY, buf,
+ ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN, 1)) {
+ free(buf);
+ return -1;
+ }
+ return ipsec_add_contact(msg);
+}
+
+/*
+ * Compare the two contacts pointed to by A and B. Return negative if
+ * *A < *B, 0 if they are equal, and positive if *A is the largest of them.
+ */
+static int
+addr_cmp(const void *a, const void *b)
+{
+ const struct contact *x = a, *y = b;
+ int minlen = MIN(x->len, y->len);
+ int rv = memcmp(x->addr, y->addr, minlen);
+
+ return rv ? rv : (x->len - y->len);
+}
+
+/*
+ * Add the peer that MSG is bound to as an address we don't want to send
+ * INITIAL CONTACT too from now on. Do not call this function with a
+ * specific address duplicate times. We want fast lookup, speed of insertion
+ * is unimportant, if this is to scale.
+ */
+static int
+ipsec_add_contact(struct message *msg)
+{
+ struct contact *new_contacts;
+ struct sockaddr *dst, *addr;
+ int cnt;
+
+ if (contact_cnt == contact_limit) {
+ cnt = contact_limit ? 2 * contact_limit : 64;
+ new_contacts = realloc(contacts, cnt * sizeof contacts[0]);
+ if (!new_contacts) {
+ log_error("ipsec_add_contact: "
+ "realloc (%p, %lu) failed", contacts,
+ cnt * (unsigned long) sizeof contacts[0]);
+ return -1;
+ }
+ contact_limit = cnt;
+ contacts = new_contacts;
+ }
+ msg->transport->vtbl->get_dst(msg->transport, &dst);
+ addr = malloc(sysdep_sa_len(dst));
+ if (!addr) {
+ log_error("ipsec_add_contact: malloc (%d) failed",
+ sysdep_sa_len(dst));
+ return -1;
+ }
+ memcpy(addr, dst, sysdep_sa_len(dst));
+ contacts[contact_cnt].addr = addr;
+ contacts[contact_cnt++].len = sysdep_sa_len(dst);
+
+ /*
+ * XXX There are better algorithms for already mostly-sorted data like
+ * this, but only qsort is standard. I will someday do this inline.
+ */
+ qsort(contacts, contact_cnt, sizeof *contacts, addr_cmp);
+ return 0;
+}
+
+/* Return true if the recipient of MSG has already been contacted. */
+static int
+ipsec_contacted(struct message *msg)
+{
+ struct contact contact;
+
+ msg->transport->vtbl->get_dst(msg->transport, &contact.addr);
+ contact.len = sysdep_sa_len(contact.addr);
+ return contacts ? (bsearch(&contact, contacts, contact_cnt,
+ sizeof *contacts, addr_cmp) != 0) : 0;
+}
+
+/* Add a HASH for to MSG. */
+u_int8_t *
+ipsec_add_hash_payload(struct message *msg, size_t hashsize)
+{
+ u_int8_t *buf;
+
+ buf = malloc(ISAKMP_HASH_SZ + hashsize);
+ if (!buf) {
+ log_error("ipsec_add_hash_payload: malloc (%lu) failed",
+ ISAKMP_HASH_SZ + (unsigned long) hashsize);
+ return 0;
+ }
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf,
+ ISAKMP_HASH_SZ + hashsize, 1)) {
+ free(buf);
+ return 0;
+ }
+ return buf;
+}
+
+/* Fill in the HASH payload of MSG. */
+int
+ipsec_fill_in_hash(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct hash *hash = hash_get(isa->hash);
+ struct prf *prf;
+ struct payload *payload;
+ u_int8_t *buf;
+ u_int32_t i;
+ char header[80];
+
+ /* If no SKEYID_a, we need not do anything. */
+ if (!isa->skeyid_a)
+ return 0;
+
+ payload = payload_first(msg, ISAKMP_PAYLOAD_HASH);
+ if (!payload) {
+ log_print("ipsec_fill_in_hash: no HASH payload found");
+ return -1;
+ }
+ buf = payload->p;
+
+ /* Allocate the prf and start calculating our HASH(1). */
+ LOG_DBG_BUF((LOG_MISC, 90, "ipsec_fill_in_hash: SKEYID_a",
+ isa->skeyid_a, isa->skeyid_len));
+ prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf)
+ return -1;
+
+ prf->Init(prf->prfctx);
+ LOG_DBG_BUF((LOG_MISC, 90, "ipsec_fill_in_hash: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN));
+ prf->Update(prf->prfctx, exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+
+ /* Loop over all payloads after HASH(1). */
+ for (i = 2; i < msg->iovlen; i++) {
+ /* XXX Misleading payload type printouts. */
+ snprintf(header, sizeof header,
+ "ipsec_fill_in_hash: payload %d after HASH(1)", i - 1);
+ LOG_DBG_BUF((LOG_MISC, 90, header, msg->iov[i].iov_base,
+ msg->iov[i].iov_len));
+ prf->Update(prf->prfctx, msg->iov[i].iov_base,
+ msg->iov[i].iov_len);
+ }
+ prf->Final(buf + ISAKMP_HASH_DATA_OFF, prf->prfctx);
+ prf_free(prf);
+ LOG_DBG_BUF((LOG_MISC, 80, "ipsec_fill_in_hash: HASH(1)", buf +
+ ISAKMP_HASH_DATA_OFF, hash->hashsize));
+
+ return 0;
+}
+
+/* Add a HASH payload to MSG, if we have an ISAKMP SA we're protected by. */
+static int
+ipsec_informational_pre_hook(struct message *msg)
+{
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa;
+ struct hash *hash;
+
+ if (!isakmp_sa)
+ return 0;
+ isa = isakmp_sa->data;
+ hash = hash_get(isa->hash);
+ return ipsec_add_hash_payload(msg, hash->hashsize) == 0;
+}
+
+/*
+ * Fill in the HASH payload in MSG, if we have an ISAKMP SA we're protected by.
+ */
+static int
+ipsec_informational_post_hook(struct message *msg)
+{
+ if (!msg->isakmp_sa)
+ return 0;
+ return ipsec_fill_in_hash(msg);
+}
+
+ssize_t
+ipsec_id_size(char *section, u_int8_t *id)
+{
+ char *type, *data;
+
+ type = conf_get_str(section, "ID-type");
+ if (!type) {
+ log_print("ipsec_id_size: section %s has no \"ID-type\" tag",
+ section);
+ return -1;
+ }
+ *id = constant_value(ipsec_id_cst, type);
+ switch (*id) {
+ case IPSEC_ID_IPV4_ADDR:
+ return sizeof(struct in_addr);
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ return 2 * sizeof(struct in_addr);
+ case IPSEC_ID_IPV6_ADDR:
+ return sizeof(struct in6_addr);
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ return 2 * sizeof(struct in6_addr);
+ case IPSEC_ID_FQDN:
+ case IPSEC_ID_USER_FQDN:
+ case IPSEC_ID_KEY_ID:
+ case IPSEC_ID_DER_ASN1_DN:
+ case IPSEC_ID_DER_ASN1_GN:
+ data = conf_get_str(section, "Name");
+ if (!data) {
+ log_print("ipsec_id_size: "
+ "section %s has no \"Name\" tag", section);
+ return -1;
+ }
+ return strlen(data);
+ }
+ log_print("ipsec_id_size: unrecognized/unsupported ID-type %d (%s)",
+ *id, type);
+ return -1;
+}
+
+/*
+ * Generate a string version of the ID.
+ */
+char *
+ipsec_id_string(u_int8_t *id, size_t id_len)
+{
+ char *buf = 0;
+ char *addrstr = 0;
+ size_t len, size;
+
+ /*
+ * XXX Real ugly way of making the offsets correct. Be aware that id
+ * now will point before the actual buffer and cannot be dereferenced
+ * without an offset larger than or equal to ISAKM_GEN_SZ.
+ */
+ id -= ISAKMP_GEN_SZ;
+
+ /* This is the actual length of the ID data field. */
+ id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF;
+
+ /*
+ * Conservative allocation.
+ * XXX I think the ASN1 DN case can be thought through to give a better
+ * estimate.
+ */
+ size = MAX(sizeof "ipv6/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ sizeof "asn1_dn/" + id_len - ISAKMP_ID_DATA_OFF);
+ buf = malloc(size);
+ if (!buf)
+ /* XXX Log? */
+ goto fail;
+
+ switch (GET_ISAKMP_ID_TYPE(id)) {
+ case IPSEC_ID_IPV4_ADDR:
+ if (id_len < sizeof(struct in_addr))
+ goto fail;
+ util_ntoa(&addrstr, AF_INET, id + ISAKMP_ID_DATA_OFF);
+ if (!addrstr)
+ goto fail;
+ snprintf(buf, size, "ipv4/%s", addrstr);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ if (id_len < sizeof(struct in6_addr))
+ goto fail;
+ util_ntoa(&addrstr, AF_INET6, id + ISAKMP_ID_DATA_OFF);
+ if (!addrstr)
+ goto fail;
+ snprintf(buf, size, "ipv6/%s", addrstr);
+ break;
+
+ case IPSEC_ID_FQDN:
+ case IPSEC_ID_USER_FQDN:
+ strlcpy(buf,
+ GET_ISAKMP_ID_TYPE(id) == IPSEC_ID_FQDN ? "fqdn/" : "ufqdn/",
+ size);
+ len = strlen(buf);
+
+ memcpy(buf + len, id + ISAKMP_ID_DATA_OFF, id_len);
+ *(buf + len + id_len) = '\0';
+ break;
+
+#ifdef USE_X509
+ case IPSEC_ID_DER_ASN1_DN:
+ strlcpy(buf, "asn1_dn/", size);
+ len = strlen(buf);
+ addrstr = x509_DN_string(id + ISAKMP_ID_DATA_OFF,
+ id_len - ISAKMP_ID_DATA_OFF);
+ if (!addrstr)
+ goto fail;
+ if (size < len + strlen(addrstr) + 1)
+ goto fail;
+ strlcpy(buf + len, addrstr, size - len);
+ break;
+#endif
+
+ default:
+ /* Unknown type. */
+ LOG_DBG((LOG_MISC, 10,
+ "ipsec_id_string: unknown identity type %d\n",
+ GET_ISAKMP_ID_TYPE(id)));
+ goto fail;
+ }
+
+ if (addrstr)
+ free(addrstr);
+ return buf;
+
+fail:
+ if (buf)
+ free(buf);
+ if (addrstr)
+ free(addrstr);
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/ipsec.h b/keyexchange/isakmpd-20041012/ipsec.h
new file mode 100644
index 0000000..1b3c996
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ipsec.h
@@ -0,0 +1,173 @@
+/* $OpenBSD: ipsec.h,v 1.24 2004/05/23 18:17:56 hshoexer Exp $ */
+/* $EOM: ipsec.h,v 1.42 2000/12/03 07:58:20 angelos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IPSEC_H_
+#define _IPSEC_H_
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "ipsec_doi.h"
+#ifdef USE_ISAKMP_CFG
+#include "isakmp_cfg.h"
+#endif
+
+struct group;
+struct hash;
+struct ike_auth;
+struct message;
+struct proto;
+struct sa;
+
+/*
+ * IPsec-specific data to be linked into the exchange struct.
+ * XXX Should probably be several different structs, one for each kind
+ * of exchange, i.e. phase 1, phase 2 and ISAKMP configuration parameters
+ * separated.
+ */
+struct ipsec_exch {
+ u_int flags;
+ struct hash *hash;
+ struct ike_auth *ike_auth;
+ struct group *group;
+ u_int16_t prf_type;
+
+ /* 0 if no KEY_EXCH was proposed, 1 otherwise */
+ u_int8_t pfs;
+
+ /*
+ * A copy of the initiator SA payload body for later computation of
+ * hashes. Phase 1 only.
+ */
+ size_t sa_i_b_len;
+ u_int8_t *sa_i_b;
+
+ /* Diffie-Hellman values. */
+ size_t g_x_len;
+ u_int8_t *g_xi;
+ u_int8_t *g_xr;
+ u_int8_t *g_xy;
+
+ /* SKEYIDs. XXX Phase 1 only? */
+ size_t skeyid_len;
+ u_int8_t *skeyid;
+ u_int8_t *skeyid_d;
+ u_int8_t *skeyid_a;
+ u_int8_t *skeyid_e;
+
+ /* HASH_I & HASH_R. XXX Do these need to be saved here? */
+ u_int8_t *hash_i;
+ u_int8_t *hash_r;
+
+ /* KEYMAT */
+ size_t keymat_len;
+
+ /* Phase 2. */
+ u_int8_t *id_ci;
+ size_t id_ci_sz;
+ u_int8_t *id_cr;
+ size_t id_cr_sz;
+
+#ifdef USE_ISAKMP_CFG
+ /* ISAKMP configuration mode parameters */
+ u_int16_t cfg_id;
+ u_int16_t cfg_type;
+ LIST_HEAD(isakmp_cfg_attr_head, isakmp_cfg_attr) attrs;
+#endif
+};
+
+#define IPSEC_EXCH_FLAG_NO_ID 1
+
+struct ipsec_sa {
+ /* Phase 1. */
+ u_int8_t hash;
+ size_t skeyid_len;
+ u_int8_t *skeyid_d;
+ u_int8_t *skeyid_a;
+ u_int16_t prf_type;
+
+ /* Phase 2. */
+ u_int16_t group_desc;
+
+ /* Tunnel parameters. These are in network byte order. */
+ struct sockaddr *src_net;
+ struct sockaddr *src_mask;
+ struct sockaddr *dst_net;
+ struct sockaddr *dst_mask;
+ u_int8_t tproto;
+ u_int16_t sport;
+ u_int16_t dport;
+};
+
+struct ipsec_proto {
+ /* Phase 2. */
+ u_int16_t encap_mode;
+ u_int16_t auth;
+ u_int16_t keylen;
+ u_int16_t keyrounds;
+
+ /* This is not negotiated, but rather configured. */
+ int32_t replay_window;
+
+ /* KEYMAT */
+ u_int8_t *keymat[2];
+};
+
+extern u_int8_t *ipsec_add_hash_payload(struct message *, size_t);
+extern int ipsec_ah_keylength(struct proto *);
+extern u_int8_t *ipsec_build_id(char *, size_t *);
+extern int ipsec_decode_attribute(u_int16_t, u_int8_t *, u_int16_t, void *);
+extern void ipsec_decode_transform(struct message *, struct sa *,
+ struct proto *, u_int8_t *);
+extern int ipsec_esp_authkeylength(struct proto *);
+extern int ipsec_esp_enckeylength(struct proto *);
+extern int ipsec_fill_in_hash(struct message *);
+extern int ipsec_gen_g_x(struct message *);
+extern int ipsec_get_id(char *, int *, struct sockaddr **,
+ struct sockaddr **, u_int8_t *, u_int16_t *);
+extern ssize_t ipsec_id_size(char *, u_int8_t *);
+extern char *ipsec_id_string(u_int8_t *, size_t);
+extern void ipsec_init(void);
+extern int ipsec_initial_contact(struct message *);
+extern int ipsec_is_attribute_incompatible(u_int16_t, u_int8_t *,
+ u_int16_t, void *);
+extern int ipsec_keymat_length(struct proto *);
+extern int ipsec_save_g_x(struct message *);
+extern struct sa *ipsec_sa_lookup(struct sockaddr *, u_int32_t, u_int8_t);
+
+extern char *ipsec_decode_ids(char *, u_int8_t *, size_t, u_int8_t *,
+ size_t, int);
+extern int ipsec_clone_id(u_int8_t **, size_t *, u_int8_t *, size_t);
+
+#endif /* _IPSEC_H_ */
diff --git a/keyexchange/isakmpd-20041012/ipsec_doi.h b/keyexchange/isakmpd-20041012/ipsec_doi.h
new file mode 100644
index 0000000..c7000c7
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ipsec_doi.h
@@ -0,0 +1,44 @@
+/* $OpenBSD: ipsec_doi.h,v 1.8 2004/04/15 18:39:25 deraadt Exp $ */
+/* $EOM: ipsec_doi.h,v 1.10 1999/04/02 00:57:51 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IPSEC_DOI_H_
+#define _IPSEC_DOI_H_
+
+#include "ipsec_fld.h"
+#include "ipsec_num.h"
+
+/* The SPI size of all IPsec protocols. XXX Correct? */
+#define IPSEC_SPI_SIZE 4
+
+/* The low limit if valid SPI values. */
+#define IPSEC_SPI_LOW 0x100
+
+#endif /* _IPSEC_DOI_H_ */
diff --git a/keyexchange/isakmpd-20041012/ipsec_fld.fld b/keyexchange/isakmpd-20041012/ipsec_fld.fld
new file mode 100644
index 0000000..8dfd0ef
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ipsec_fld.fld
@@ -0,0 +1,60 @@
+# $OpenBSD: ipsec_fld.fld,v 1.5 2003/06/03 14:28:16 ho Exp $
+# $EOM: ipsec_fld.fld,v 1.1 1998/08/02 20:12:02 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# XXX There are num-declared fields below that really are csts.
+
+# IPsec's situation field's subdivision.
+IPSEC_SIT
+ SIT mask 4 ipsec_sit_cst
+ LABELED_DOMAIN_ID num 4
+ SECRECY_LENGTH num 2
+ RESERVED_1 ign 2
+# The following fields' offsets need the secrecy length added + 32bit
+# alignment.
+ SECRECY_CAT_LENGTH num 2
+ RESERVED_2 ign 2
+# The following fields' offsets need the secrecy cat length added + 32bit
+# alignment on top of the aforementioned offset.
+ INTEGRITY_LENGTH num 2
+ RESERVED_3 ign 2
+# The following fields' offsets need the integrity length added + 32bit
+# alignment on top of the aforementioned offset.
+ INTEGRITY_CAT_LENGTH num 2
+ RESERVED_4 ign 2
+# The IPSEC_SIT record's length need the integrity cat length added + 32bit
+# alignment on top of the aforementioned offset.
+.
+
+# IPsec's layout of the identification payload's DOI data field.
+IPSEC_ID
+ PROTO num 1
+ PORT num 2
+.
diff --git a/keyexchange/isakmpd-20041012/ipsec_num.cst b/keyexchange/isakmpd-20041012/ipsec_num.cst
new file mode 100644
index 0000000..9105550
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ipsec_num.cst
@@ -0,0 +1,264 @@
+# $OpenBSD: ipsec_num.cst,v 1.15 2004/04/28 14:40:00 ho Exp $
+# $EOM: ipsec_num.cst,v 1.5 2000/10/13 17:56:52 angelos Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+# Copyright (c) 2003 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# XXX Please fill in references to the drafts, chapter & verse for each
+# constant group below.
+
+# IPSEC DOI Identifier.
+IPSEC_DOI
+ IPSEC 1
+.
+
+# IPSEC SA attributes
+IPSEC_ATTR
+ SA_LIFE_TYPE 1
+ SA_LIFE_DURATION 2
+ GROUP_DESCRIPTION 3
+ ENCAPSULATION_MODE 4
+ AUTHENTICATION_ALGORITHM 5
+ KEY_LENGTH 6
+ KEY_ROUNDS 7
+ COMPRESS_DICTIONARY_SIZE 8
+ COMPRESS_PRIVATE_ALGORITHM 9
+ ECN_TUNNEL 10
+.
+
+# IPSEC SA duration.
+IPSEC_DURATION
+ SECONDS 1
+ KILOBYTES 2
+.
+
+# IPSEC encapsulation mode.
+IPSEC_ENCAP
+ TUNNEL 1
+ TRANSPORT 2
+ UDP_ENCAP_TUNNEL 3
+ UDP_ENCAP_TRANSPORT 4
+ UDP_ENCAP_TUNNEL_DRAFT 61443 # draft-ietf-ipsec-nat-t-ike
+ UDP_ENCAP_TRANSPORT_DRAFT 61443 # draft-ietf-ipsec-nat-t-ike
+.
+
+# IPSEC authentication algorithm.
+IPSEC_AUTH
+ HMAC_MD5 1
+ HMAC_SHA 2
+ DES_MAC 3
+ KPDK 4
+ HMAC_SHA2_256 5
+ HMAC_SHA2_384 6
+ HMAC_SHA2_512 7
+ HMAC_RIPEMD 8
+.
+
+# IPSEC ID types.
+IPSEC_ID
+ IPV4_ADDR 1
+ FQDN 2
+ USER_FQDN 3
+ IPV4_ADDR_SUBNET 4
+ IPV6_ADDR 5
+ IPV6_ADDR_SUBNET 6
+ IPV4_RANGE 7
+ IPV6_RANGE 8
+ DER_ASN1_DN 9
+ DER_ASN1_GN 10
+ KEY_ID 11
+.
+
+# IKE SA attributes
+IKE_ATTR
+ ENCRYPTION_ALGORITHM 1 ike_encrypt_cst
+ HASH_ALGORITHM 2 ike_hash_cst
+ AUTHENTICATION_METHOD 3 ike_auth_cst
+ GROUP_DESCRIPTION 4 ike_group_desc_cst
+ GROUP_TYPE 5 ike_group_cst
+ GROUP_PRIME 6
+ GROUP_GENERATOR_1 7
+ GROUP_GENERATOR_2 8
+ GROUP_CURVE_A 9
+ GROUP_CURVE_B 10
+ LIFE_TYPE 11 ike_duration_cst
+ LIFE_DURATION 12
+ PRF 13 ike_prf_cst
+ KEY_LENGTH 14
+ FIELD_SIZE 15
+ GROUP_ORDER 16
+ BLOCK_SIZE 17
+.
+
+# XXX Fill in reserved ranges for the attributes below.
+
+# IKE encryption algorithm.
+IKE_ENCRYPT
+ DES_CBC 1
+ IDEA_CBC 2
+ BLOWFISH_CBC 3
+ RC5_R16_B64_CBC 4
+ 3DES_CBC 5
+ CAST_CBC 6
+ AES_CBC 7
+.
+
+# IKE hash algorithm.
+IKE_HASH
+ MD5 1
+ SHA 2
+ TIGER 3
+ SHA2_256 4
+ SHA2_384 5
+ SHA2_512 6
+.
+
+# IKE authentication method.
+IKE_AUTH
+ PRE_SHARED 1
+ DSS 2
+ RSA_SIG 3
+ RSA_ENC 4
+ RSA_ENC_REV 5
+ EL_GAMAL_ENC 6
+ EL_GAMAL_ENC_REV 7
+ ECDSA_SIG 8
+.
+
+# IKE group description.
+IKE_GROUP_DESC
+ MODP_768 1
+ MODP_1024 2
+ EC2N_155 3
+ EC2N_185 4
+ MODP_1536 5
+ EC2N_163sect 6
+ EC2N_163K 7
+ EC2N_283sect 8
+ EC2N_283K 9
+ EC2N_409sect 10
+ EC2N_409K 11
+ EC2N_571sect 12
+ EC2N_571K 13
+ MODP_2048 14
+ MODP_3072 15
+ MODP_4096 16
+ MODP_6144 17
+ MODP_8192 18
+.
+
+# IKE Group type.
+IKE_GROUP
+ MODP 1
+ ECP 2
+ EC2N 3
+.
+
+# IKE SA duration.
+IKE_DURATION
+ SECONDS 1
+ KILOBYTES 2
+.
+
+# IKE Pseudo random function. No defined so far.
+IKE_PRF
+.
+
+# IPSEC Situation bits.
+IPSEC_SIT
+ IDENTITY_ONLY 1
+ SECRECY 2
+ INTEGRITY 4
+.
+
+# IPSEC security protocol IDs.
+IPSEC_PROTO
+ IPSEC_AH 2
+ IPSEC_ESP 3
+ IPCOMP 4
+.
+
+# IPSEC ISAKMP transform IDs.
+IPSEC_TRANSFORM
+ KEY_IKE 1
+.
+
+# IPSEC AH transform IDs.
+IPSEC_AH
+ MD5 2
+ SHA 3
+ DES 4
+ SHA2_256 5
+ SHA2_384 6
+ SHA2_512 7
+ RIPEMD 8
+.
+
+# IPSEC ESP transform IDs.
+IPSEC_ESP
+ DES_IV64 1
+ DES 2
+ 3DES 3
+ RC5 4
+ IDEA 5
+ CAST 6
+ BLOWFISH 7
+ 3IDEA 8
+ DES_IV32 9
+ RC4 10
+ NULL 11
+ AES 12
+ AES_128_CTR 13
+ AES_MARS 249
+ AES_RC6 250
+ AES_RIJNDAEL 251
+ AES_SERPENT 252
+ AES_TWOFISH 253
+.
+
+# IPSEC IPCOMP transform IDs
+IPSEC_IPCOMP
+ OUI 1
+ DEFLATE 2
+ LZS 3
+ V42BIS 4
+.
+
+# IPSEC notify message types.
+IPSEC_NOTIFY
+ RESPONDER_LIFETIME 24576
+ REPLAY_STATUS 24577
+ INITIAL_CONTACT 24578
+.
+
+# IKE exchange types.
+IKE_EXCH
+ QUICK_MODE 32
+ NEW_GROUP_MODE 33
+.
diff --git a/keyexchange/isakmpd-20041012/isakmp.h b/keyexchange/isakmpd-20041012/isakmp.h
new file mode 100644
index 0000000..4ab6869
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmp.h
@@ -0,0 +1,64 @@
+/* $OpenBSD: isakmp.h,v 1.7 2004/06/20 15:24:05 ho Exp $ */
+/* $EOM: isakmp.h,v 1.11 2000/07/05 10:48:43 ho Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _ISAKMP_H_
+#define _ISAKMP_H_
+
+#include "isakmp_fld.h"
+#include "isakmp_num.h"
+
+/* IANA assigned port */
+#define UDP_DEFAULT_PORT 500
+#define UDP_DEFAULT_PORT_STR "500"
+
+#define ISAKMP_DEFAULT_TRANSPORT "udp"
+
+/* draft-ietf-ipsec-nat-t-ike-07.txt */
+#define UDP_ENCAP_DEFAULT_PORT 4500
+#define UDP_ENCAP_DEFAULT_PORT_STR "4500"
+
+/* ISAKMP header extras defines */
+#define ISAKMP_HDR_COOKIES_OFF ISAKMP_HDR_ICOOKIE_OFF
+#define ISAKMP_HDR_COOKIES_LEN (ISAKMP_HDR_ICOOKIE_LEN \
+ + ISAKMP_HDR_ICOOKIE_LEN)
+
+/* ISAKMP attribute utilitiy macros. */
+#define ISAKMP_ATTR_FORMAT(x) ((x) >> 15)
+#define ISAKMP_ATTR_TYPE(x) ((x) & 0x7fff)
+#define ISAKMP_ATTR_MAKE(fmt, type) (((fmt) << 15) | (type))
+
+/* Version number handling. */
+#define ISAKMP_VERSION_MAJOR(x) ((x) >> 4)
+#define ISAKMP_VERSION_MINOR(x) ((x) & 0xf)
+#define ISAKMP_VERSION_MAKE(maj, min) ((maj) << 4 | (min))
+
+#endif /* _ISAKMP_H_ */
diff --git a/keyexchange/isakmpd-20041012/isakmp_cfg.c b/keyexchange/isakmpd-20041012/isakmp_cfg.c
new file mode 100644
index 0000000..222d0c6
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmp_cfg.c
@@ -0,0 +1,982 @@
+/* $OpenBSD: isakmp_cfg.c,v 1.34 2004/08/08 19:11:06 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2002 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Gatespace
+ * (http://www.gatespace.com/).
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <bitstring.h>
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "conf.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ipsec.h"
+#include "isakmp_fld.h"
+#include "isakmp_num.h"
+#include "log.h"
+#include "message.h"
+#include "prf.h"
+#include "sa.h"
+#include "transport.h"
+#include "util.h"
+
+/*
+ * Validation script used to test messages for correct content of
+ * payloads depending on the exchange type.
+ */
+int16_t script_transaction[] = {
+ ISAKMP_PAYLOAD_ATTRIBUTE, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_ATTRIBUTE, /* Responder -> initiator. */
+ EXCHANGE_SCRIPT_END
+};
+
+static int cfg_decode_attribute(u_int16_t, u_int8_t *, u_int16_t, void *);
+static int cfg_encode_attributes(struct isakmp_cfg_attr_head *, u_int32_t,
+ u_int32_t, char *, u_int8_t **, u_int16_t *);
+static int cfg_initiator_send_ATTR(struct message *);
+static int cfg_initiator_recv_ATTR(struct message *);
+static int cfg_responder_recv_ATTR(struct message *);
+static int cfg_responder_send_ATTR(struct message *);
+
+u_int8_t *cfg_add_hash(struct message *);
+int cfg_finalize_hash(struct message *, u_int8_t *, u_int8_t *,
+ u_int16_t);
+int cfg_verify_hash(struct message *);
+
+/* Server: SET/ACK Client; REQ/REPLY */
+int (*isakmp_cfg_initiator[]) (struct message *) = {
+ cfg_initiator_send_ATTR,
+ cfg_initiator_recv_ATTR
+};
+
+/* Server: REQ/REPLY Client: SET/ACK */
+int (*isakmp_cfg_responder[]) (struct message *) = {
+ cfg_responder_recv_ATTR,
+ cfg_responder_send_ATTR
+};
+
+/*
+ * When we are "the server", this starts SET/ACK mode
+ * When we are "the client", this starts REQ/REPLY mode
+ */
+static int
+cfg_initiator_send_ATTR(struct message *msg)
+{
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_exch *ie = msg->exchange->data;
+ u_int8_t *hashp = 0, *attrp, *attr;
+ size_t attrlen, off;
+ char *id_string, *cfg_mode, *field;
+ struct sockaddr *sa;
+#define CFG_ATTR_BIT_MAX ISAKMP_CFG_ATTR_FUTURE_MIN /* XXX */
+ bitstr_t bit_decl(attrbits, CFG_ATTR_BIT_MAX);
+ u_int16_t bit, length;
+ u_int32_t life;
+
+ if (msg->exchange->phase == 2) {
+ hashp = cfg_add_hash(msg);
+ if (!hashp)
+ return -1;
+ }
+ /* We initiated this exchange, check isakmp_sa for other side. */
+ if (isakmp_sa->initiator)
+ id_string = ipsec_id_string(isakmp_sa->id_r,
+ isakmp_sa->id_r_len);
+ else
+ id_string = ipsec_id_string(isakmp_sa->id_i,
+ isakmp_sa->id_i_len);
+ if (!id_string) {
+ log_print("cfg_initiator_send_ATTR: cannot parse ID");
+ goto fail;
+ }
+ /* Check for attribute list to send to the other side */
+ attrlen = 0;
+ bit_nclear(attrbits, 0, CFG_ATTR_BIT_MAX - 1);
+
+ cfg_mode = conf_get_str(id_string, "Mode");
+ if (!cfg_mode || strcmp(cfg_mode, "SET") == 0) {
+ /* SET/ACK mode */
+ ie->cfg_type = ISAKMP_CFG_SET;
+
+ LOG_DBG((LOG_NEGOTIATION, 10,
+ "cfg_initiator_send_ATTR: SET/ACK mode"));
+
+#define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do \
+ { \
+ if ((sa = conf_get_address (id_string, STR)) != NULL) \
+ switch (sa->sa_family) { \
+ case AF_INET: \
+ bit_set (attrbits, ATTR4); \
+ attrlen += ISAKMP_ATTR_SZ + LEN4; \
+ break; \
+ case AF_INET6: \
+ bit_set (attrbits, ATTR6); \
+ attrlen += ISAKMP_ATTR_SZ + LEN6; \
+ break; \
+ default: \
+ break; \
+ } \
+ free (sa); \
+ } while (0)
+
+ /*
+ * XXX We don't simultaneously support IPv4 and IPv6
+ * addresses.
+ */
+ ATTRFIND("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS, 4,
+ ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16);
+ ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4,
+ ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16);
+ ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4,
+ ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16);
+ ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4,
+ ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16);
+ ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4,
+ ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16);
+#ifdef notyet
+ ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8,
+ ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17);
+#endif
+#undef ATTRFIND
+
+ if (conf_get_str(id_string, "Lifetime")) {
+ bit_set(attrbits,
+ ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);
+ attrlen += ISAKMP_ATTR_SZ + 4;
+ }
+ } else {
+ struct conf_list *alist;
+ struct conf_list_node *anode;
+
+ ie->cfg_type = ISAKMP_CFG_REQUEST;
+
+ LOG_DBG((LOG_NEGOTIATION, 10,
+ "cfg_initiator_send_ATTR: REQ/REPLY mode"));
+
+ alist = conf_get_list(id_string, "Attributes");
+ if (alist) {
+ for (anode = TAILQ_FIRST(&alist->fields); anode;
+ anode = TAILQ_NEXT(anode, link)) {
+ if (strcasecmp(anode->field, "Address") == 0) {
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS);
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS);
+ attrlen += ISAKMP_ATTR_SZ * 2;
+ } else if (strcasecmp(anode->field, "Netmask")
+ == 0) {
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK);
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK);
+ attrlen += ISAKMP_ATTR_SZ * 2;
+ } else if (strcasecmp(anode->field,
+ "Nameserver") == 0) {
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS);
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS);
+ attrlen += ISAKMP_ATTR_SZ * 2;
+ } else if (strcasecmp(anode->field,
+ "WINS-server") == 0) {
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS);
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS);
+ attrlen += ISAKMP_ATTR_SZ * 2;
+ } else if (strcasecmp(anode->field,
+ "DHCP-server") == 0) {
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP);
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP);
+ attrlen += ISAKMP_ATTR_SZ * 2;
+ } else if (strcasecmp(anode->field,
+ "Lifetime") == 0) {
+ bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);
+ attrlen += ISAKMP_ATTR_SZ;
+ } else {
+ log_print("cfg_initiator_send_ATTR: "
+ "unknown attribute %.20s in "
+ "section [%s]", anode->field,
+ id_string);
+ }
+ }
+
+ conf_free_list(alist);
+ }
+ }
+
+ if (attrlen == 0) {
+ /* No data found. */
+ log_print("cfg_initiator_send_ATTR: no IKECFG attributes "
+ "found for [%s]", id_string);
+
+ /*
+ * We can continue, but this indicates a configuration error
+ * that the user probably will want to correct.
+ */
+ free(id_string);
+ return 0;
+ }
+ attrlen += ISAKMP_ATTRIBUTE_SZ;
+ attrp = calloc(1, attrlen);
+ if (!attrp) {
+ log_error("cfg_initiator_send_ATTR: calloc (1, %lu) failed",
+ (unsigned long)attrlen);
+ goto fail;
+ }
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen,
+ 1)) {
+ free(attrp);
+ goto fail;
+ }
+ SET_ISAKMP_ATTRIBUTE_TYPE(attrp, ie->cfg_type);
+ getrandom((u_int8_t *) & ie->cfg_id, sizeof ie->cfg_id);
+ SET_ISAKMP_ATTRIBUTE_ID(attrp, ie->cfg_id);
+
+ off = ISAKMP_ATTRIBUTE_SZ;
+
+ /*
+ * Use the bitstring built previously to collect the right
+ * parameters for attrp.
+ */
+ for (bit = 0; bit < CFG_ATTR_BIT_MAX; bit++)
+ if (bit_test(attrbits, bit)) {
+ attr = attrp + off;
+ SET_ISAKMP_ATTR_TYPE(attr, bit);
+
+ if (ie->cfg_type == ISAKMP_CFG_REQUEST) {
+ off += ISAKMP_ATTR_SZ;
+ continue;
+ }
+ /* All the other are similar, this is the odd one. */
+ if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY) {
+ life = conf_get_num(id_string, "Lifetime",
+ 1200);
+ SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4);
+ encode_32(attr + ISAKMP_ATTR_VALUE_OFF, life);
+ off += ISAKMP_ATTR_SZ + 4;
+ continue;
+ }
+ switch (bit) {
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
+ length = 4;
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
+ length = 16;
+ break;
+
+ default:
+ length = 0; /* Silence gcc. */
+ }
+
+ switch (bit) {
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
+ field = "Address";
+ break;
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
+ field = "Netmask";
+ break;
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
+ field = "Nameserver";
+ break;
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
+ field = "DHCP-server";
+ break;
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
+ field = "WINS-server";
+ break;
+ default:
+ field = 0; /* Silence gcc. */
+ }
+
+ sa = conf_get_address(id_string, field);
+
+ SET_ISAKMP_ATTR_LENGTH_VALUE(attr, length);
+ memcpy(attr + ISAKMP_ATTR_VALUE_OFF,
+ sockaddr_addrdata(sa), length);
+
+ free(sa);
+
+ off += ISAKMP_ATTR_SZ + length;
+ }
+ if (msg->exchange->phase == 2)
+ if (cfg_finalize_hash(msg, hashp, attrp, attrlen))
+ goto fail;
+
+ return 0;
+
+fail:
+ if (id_string)
+ free(id_string);
+ return -1;
+}
+
+/*
+ * As "the server", this ends SET/ACK.
+ * As "the client", this ends REQ/REPLY.
+ */
+static int
+cfg_initiator_recv_ATTR(struct message *msg)
+{
+ struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE);
+ struct ipsec_exch *ie = msg->exchange->data;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct isakmp_cfg_attr *attr;
+ struct sockaddr *sa;
+ const char *uk_addr = "<unknown>";
+ char *addr;
+
+ if (msg->exchange->phase == 2)
+ if (cfg_verify_hash(msg))
+ return -1;
+
+ /* Sanity. */
+ if (ie->cfg_id != GET_ISAKMP_ATTRIBUTE_ID(attrp->p)) {
+ log_print("cfg_initiator_recv_ATTR: "
+ "cfg packet ID does not match!");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
+ return -1;
+ }
+ switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]) {
+ case ISAKMP_CFG_ACK:
+ if (ie->cfg_type != ISAKMP_CFG_SET) {
+ log_print("cfg_initiator_recv_ATTR: "
+ "bad packet type ACK");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
+ 0, 1, 0);
+ return -1;
+ }
+ break;
+ case ISAKMP_CFG_REPLY:
+ if (ie->cfg_type != ISAKMP_CFG_REQUEST) {
+ log_print("cfg_initiator_recv_ATTR: "
+ "bad packet type REPLY");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
+ 0, 1, 0);
+ return -1;
+ }
+ break;
+
+ default:
+ log_print("cfg_initiator_recv_ATTR: unexpected configuration "
+ "message type %d", attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]);
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
+ return -1;
+ }
+
+ attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ cfg_decode_attribute, ie);
+
+ switch (ie->cfg_type) {
+ case ISAKMP_CFG_ACK: {
+ /* SET/ACK -- Server side (ACK from client) */
+ msg->transport->vtbl->get_src(isakmp_sa->transport,
+ &sa);
+ if (sockaddr2text(sa, &addr, 0) < 0)
+ addr = (char *) uk_addr;
+
+ for (attr = LIST_FIRST(&ie->attrs); attr;
+ attr = LIST_NEXT(attr, link))
+ LOG_DBG((LOG_NEGOTIATION, 50,
+ "cfg_initiator_recv_ATTR: "
+ "client %s ACKs attribute %s", addr,
+ constant_name(isakmp_cfg_attr_cst,
+ attr->type)));
+
+ if (addr != uk_addr)
+ free(addr);
+ }
+ break;
+
+ case ISAKMP_CFG_REPLY: {
+ /*
+ * REQ/REPLY: effect attributes we've gotten
+ * responses on.
+ */
+ msg->transport->vtbl->get_src(isakmp_sa->transport,
+ &sa);
+ if (sockaddr2text(sa, &addr, 0) < 0)
+ addr = (char *) uk_addr;
+
+ for (attr = LIST_FIRST(&ie->attrs); attr;
+ attr = LIST_NEXT(attr, link))
+ LOG_DBG((LOG_NEGOTIATION, 50,
+ "cfg_initiator_recv_ATTR: "
+ "server %s replied with attribute %s",
+ addr, constant_name(isakmp_cfg_attr_cst,
+ attr->type)));
+
+ if (addr != uk_addr)
+ free(addr);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ attrp->flags |= PL_MARK;
+ return 0;
+}
+
+/*
+ * As "the server", this starts REQ/REPLY (initiated by the client).
+ * As "the client", this starts SET/ACK (initiated by the server).
+ */
+static int
+cfg_responder_recv_ATTR(struct message *msg)
+{
+ struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE);
+ struct ipsec_exch *ie = msg->exchange->data;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct isakmp_cfg_attr *attr;
+ struct sockaddr *sa;
+ char *addr;
+
+ if (msg->exchange->phase == 2)
+ if (cfg_verify_hash(msg))
+ return -1;
+
+ ie->cfg_id = GET_ISAKMP_ATTRIBUTE_ID(attrp->p);
+ ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF];
+
+ switch (ie->cfg_type) {
+ case ISAKMP_CFG_REQUEST:
+ case ISAKMP_CFG_SET:
+ break;
+
+ default:
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
+ log_print("cfg_responder_recv_ATTR: "
+ "unexpected configuration message type %d", ie->cfg_type);
+ return -1;
+ }
+
+ attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ cfg_decode_attribute, ie);
+
+ switch (ie->cfg_type) {
+ case ISAKMP_CFG_REQUEST:
+ /* We're done. */
+ break;
+
+ case ISAKMP_CFG_SET: {
+ /* SET/ACK -- Client side (SET from server) */
+ const char *uk_addr = "<unknown>";
+
+ msg->transport->vtbl->get_dst(isakmp_sa->transport,
+ &sa);
+ if (sockaddr2text(sa, &addr, 0) < 0)
+ addr = (char *) uk_addr;
+
+ for (attr = LIST_FIRST(&ie->attrs); attr;
+ attr = LIST_NEXT(attr, link))
+ LOG_DBG((LOG_NEGOTIATION, 50,
+ "cfg_responder_recv_ATTR: "
+ "server %s asks us to SET attribute %s",
+ addr, constant_name(isakmp_cfg_attr_cst,
+ attr->type)));
+
+ /*
+ * XXX Here's the place to add code to walk through
+ * XXX each attribute and send them along to dhclient
+ * XXX or whatever. Each attribute that we act upon
+ * XXX (such as setting a netmask), should be marked
+ * XXX like this for us to send the proper ACK
+ * XXX response: attr->attr_used++;
+ */
+
+ if (addr != uk_addr)
+ free(addr);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ attrp->flags |= PL_MARK;
+ return 0;
+}
+
+/*
+ * As "the server", this ends REQ/REPLY mode.
+ * As "the client", this ends SET/ACK mode.
+ */
+static int
+cfg_responder_send_ATTR(struct message *msg)
+{
+ struct ipsec_exch *ie = msg->exchange->data;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ u_int8_t *hashp = 0, *attrp;
+ u_int16_t attrlen;
+ char *id_string;
+
+ if (msg->exchange->phase == 2) {
+ hashp = cfg_add_hash(msg);
+ if (!hashp)
+ return -1;
+ }
+ /* We are responder, check isakmp_sa for other side. */
+ if (isakmp_sa->initiator ^ (ie->cfg_type == ISAKMP_CFG_REQUEST))
+ id_string = ipsec_id_string(isakmp_sa->id_i,
+ isakmp_sa->id_i_len);
+ else
+ id_string = ipsec_id_string(isakmp_sa->id_r,
+ isakmp_sa->id_r_len);
+ if (!id_string) {
+ log_print("cfg_responder_send_ATTR: cannot parse client's ID");
+ return -1;
+ }
+ if (cfg_encode_attributes(&ie->attrs, (ie->cfg_type == ISAKMP_CFG_SET ?
+ ISAKMP_CFG_ACK : ISAKMP_CFG_REPLY), ie->cfg_id, id_string, &attrp,
+ &attrlen)) {
+ free(id_string);
+ return -1;
+ }
+ free(id_string);
+
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen,
+ 1)) {
+ free(attrp);
+ return -1;
+ }
+ if (msg->exchange->phase == 2)
+ if (cfg_finalize_hash(msg, hashp, attrp, attrlen))
+ return -1;
+
+ return 0;
+}
+
+u_int8_t *
+cfg_add_hash(struct message *msg)
+{
+ struct ipsec_sa *isa = msg->isakmp_sa->data;
+ struct hash *hash = hash_get(isa->hash);
+ u_int8_t *hashp;
+
+ hashp = malloc(ISAKMP_HASH_SZ + hash->hashsize);
+ if (!hashp) {
+ log_error("cfg_add_hash: malloc (%lu) failed",
+ ISAKMP_HASH_SZ + (unsigned long)hash->hashsize);
+ return 0;
+ }
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, hashp,
+ ISAKMP_HASH_SZ + hash->hashsize, 1)) {
+ free(hashp);
+ return 0;
+ }
+ return hashp;
+}
+
+int
+cfg_finalize_hash(struct message *msg, u_int8_t *hashp, u_int8_t *data,
+ u_int16_t length)
+{
+ struct ipsec_sa *isa = msg->isakmp_sa->data;
+ struct prf *prf;
+
+ prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf)
+ return -1;
+
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, msg->exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ prf->Update(prf->prfctx, data, length);
+ prf->Final(hashp + ISAKMP_GEN_SZ, prf->prfctx);
+ prf_free(prf);
+ return 0;
+}
+
+int
+cfg_verify_hash(struct message *msg)
+{
+ struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH);
+ struct ipsec_sa *isa = msg->isakmp_sa->data;
+ struct prf *prf;
+ u_int8_t *hash, *comp_hash;
+ size_t hash_len;
+
+ if (!hashp) {
+ log_print("cfg_verify_hash: phase 2 message missing HASH");
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
+ 0, 1, 0);
+ return -1;
+ }
+ hash = hashp->p;
+ hash_len = GET_ISAKMP_GEN_LENGTH(hash);
+ comp_hash = malloc(hash_len - ISAKMP_GEN_SZ);
+ if (!comp_hash) {
+ log_error("cfg_verify_hash: malloc (%lu) failed",
+ (unsigned long)hash_len - ISAKMP_GEN_SZ);
+ return -1;
+ }
+ /* Verify hash. */
+ prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf) {
+ free(comp_hash);
+ return -1;
+ }
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, msg->exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ prf->Update(prf->prfctx, hash + hash_len,
+ msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len);
+ prf->Final(comp_hash, prf->prfctx);
+ prf_free(prf);
+
+ if (memcmp(hash + ISAKMP_GEN_SZ, comp_hash, hash_len - ISAKMP_GEN_SZ)
+ != 0) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
+ 0, 1, 0);
+ free(comp_hash);
+ return -1;
+ }
+ free(comp_hash);
+
+ /* Mark the HASH as handled. */
+ hashp->flags |= PL_MARK;
+
+ /* Mark message authenticated. */
+ msg->flags |= MSG_AUTHENTICATED;
+
+ return 0;
+}
+
+/*
+ * Decode the attribute of type TYPE with a LEN length value pointed to by
+ * VALUE. VIE is a pointer to the IPsec exchange context holding the
+ * attributes indexed by type for easy retrieval.
+ */
+static int
+cfg_decode_attribute(u_int16_t type, u_int8_t * value, u_int16_t len,
+ void *vie)
+{
+ struct ipsec_exch *ie = vie;
+ struct isakmp_cfg_attr *attr;
+
+ if (type >= ISAKMP_CFG_ATTR_PRIVATE_MIN
+ && type <= ISAKMP_CFG_ATTR_PRIVATE_MAX)
+ return 0;
+ if (type == 0 || type >= ISAKMP_CFG_ATTR_FUTURE_MIN) {
+ LOG_DBG((LOG_NEGOTIATION, 30,
+ "cfg_decode_attribute: invalid attr type %u", type));
+ return -1;
+ }
+ attr = calloc(1, sizeof *attr);
+ if (!attr) {
+ log_error("cfg_decode_attribute: calloc (1, %lu) failed",
+ (unsigned long)sizeof *attr);
+ return -1;
+ }
+ attr->type = type;
+ attr->length = len;
+ if (len) {
+ attr->value = malloc(len);
+ if (!attr->value) {
+ log_error("cfg_decode_attribute: malloc (%d) failed",
+ len);
+ free(attr);
+ /* Should we also deallocate all other values? */
+ return -1;
+ }
+ memcpy(attr->value, value, len);
+ }
+ LIST_INSERT_HEAD(&ie->attrs, attr, link);
+ return 0;
+}
+
+/*
+ * Encode list of attributes from ie->attrs into a attribute payload.
+ */
+static int
+cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type,
+ u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len)
+{
+ struct isakmp_cfg_attr *attr;
+ struct sockaddr *sa;
+ sa_family_t family;
+ u_int32_t value;
+ u_int16_t off;
+ char *field;
+
+ /* Compute length */
+ *len = ISAKMP_ATTRIBUTE_SZ;
+ for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
+ /* With ACK we only include the attrs we've actually used. */
+ if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
+ continue;
+
+ switch (attr->type) {
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
+ attr->length = 4;
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
+ attr->length = 8;
+ break;
+
+ case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
+ /* XXX So far no version identifier of isakmpd here. */
+ attr->length = 0;
+ break;
+
+ case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
+ attr->length = 2 * 15;
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
+ attr->length = 16;
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
+ attr->length = 17;
+ break;
+
+ default:
+ attr->ignore++;
+ /* XXX Log! */
+ }
+ *len += ISAKMP_ATTR_SZ + attr->length;
+ }
+
+ /* Allocate enough space for the payload */
+ *attrp = calloc(1, *len);
+ if (!*attrp) {
+ log_error("cfg_encode_attributes: calloc (1, %lu) failed",
+ (unsigned long)*len);
+ return -1;
+ }
+ SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type);
+ SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id);
+
+ off = ISAKMP_ATTRIBUTE_SZ;
+ for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
+ /* With ACK we only include the attrs we've actually used. */
+ if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
+ continue;
+
+ switch (attr->type) {
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
+ family = AF_INET;
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
+ family = AF_INET6;
+ break;
+
+ default:
+ family = 0;
+ break;
+ }
+
+ switch (attr->type) {
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
+ field = "Address";
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
+ field = "Network"; /* XXX or just "Address" */
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
+ field = "Netmask";
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
+ field = "DHCP-server";
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
+ field = "Nameserver";
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
+ field = "WINS-server";
+ break;
+
+ default:
+ field = 0;
+ }
+
+ switch (attr->type) {
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
+ case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
+ sa = conf_get_address(id_string, field);
+ if (!sa) {
+ LOG_DBG((LOG_NEGOTIATION, 10,
+ "cfg_responder_send_ATTR: "
+ "attribute not found: %s", field));
+ attr->length = 0;
+ break;
+ }
+ if (sa->sa_family != family) {
+ log_print("cfg_responder_send_ATTR: "
+ "attribute %s - expected %s got %s data",
+ field,
+ (family == AF_INET ? "IPv4" : "IPv6"),
+ (sa->sa_family ==
+ AF_INET ? "IPv4" : "IPv6"));
+ free(sa);
+ attr->length = 0;
+ break;
+ }
+ /* Temporary limit length for the _SUBNET types. */
+ if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET)
+ attr->length = 4;
+ else if (attr->type ==
+ ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET)
+ attr->length = 16;
+
+ memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF,
+ sockaddr_addrdata(sa), attr->length);
+ free(sa);
+
+ /* _SUBNET types need some extra work. */
+ if (attr->type ==
+ ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) {
+ sa = conf_get_address(id_string, "Netmask");
+ if (!sa) {
+ LOG_DBG((LOG_NEGOTIATION, 10,
+ "cfg_responder_send_ATTR: "
+ "attribute not found: Netmask"));
+ attr->length = 0;
+ break;
+ }
+ if (sa->sa_family != AF_INET) {
+ log_print("cfg_responder_send_ATTR: "
+ "attribute Netmask - expected "
+ "IPv4 got IPv6 data");
+ free(sa);
+ attr->length = 0;
+ break;
+ }
+ memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF +
+ attr->length, sockaddr_addrdata(sa),
+ attr->length);
+ attr->length = 8;
+ free(sa);
+ } else if (attr->type ==
+ ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) {
+ int prefix = conf_get_num(id_string, "Prefix",
+ -1);
+
+ if (prefix == -1) {
+ log_print("cfg_responder_send_ATTR: "
+ "attribute not found: Prefix");
+ attr->length = 0;
+ break;
+ } else if (prefix < -1 || prefix > 128) {
+ log_print("cfg_responder_send_ATTR: "
+ "attribute Prefix - invalid "
+ "value %d", prefix);
+ attr->length = 0;
+ break;
+ }
+ *(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 16) =
+ (u_int8_t)prefix;
+ attr->length = 17;
+ }
+ break;
+
+ case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
+ value = conf_get_num(id_string, "Lifetime", 1200);
+ encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value);
+ break;
+
+ case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
+ /* XXX So far no version identifier of isakmpd here. */
+ break;
+
+ case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
+ break;
+
+ default:
+ break;
+ }
+
+ SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type);
+ SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length);
+ off += ISAKMP_ATTR_VALUE_OFF + attr->length;
+ }
+
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/isakmp_cfg.h b/keyexchange/isakmpd-20041012/isakmp_cfg.h
new file mode 100644
index 0000000..169fa29
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmp_cfg.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: isakmp_cfg.h,v 1.5 2004/05/23 18:17:56 hshoexer Exp $ */
+
+/*
+ * Copyright (c) 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Gatespace
+ * (http://www.gatespace.com/).
+ */
+
+#ifndef _ISAKMP_CFG_H_
+#define _ISAKMP_CFG_H_
+
+#include <sys/queue.h>
+
+struct isakmp_cfg_attr {
+ LIST_ENTRY(isakmp_cfg_attr) link;
+ u_int16_t type;
+ u_int8_t attr_used;
+ /* 8 bits just to be well-aligned. */
+ u_int8_t ignore;
+ size_t length;
+ void *value;
+};
+
+struct message;
+
+extern int (*isakmp_cfg_initiator[])(struct message *);
+extern int (*isakmp_cfg_responder[])(struct message *);
+extern int16_t script_transaction[];
+
+#endif /* _ISAKMP_CFG_H_ */
diff --git a/keyexchange/isakmpd-20041012/isakmp_doi.c b/keyexchange/isakmpd-20041012/isakmp_doi.c
new file mode 100644
index 0000000..2fc8c1d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmp_doi.c
@@ -0,0 +1,264 @@
+/* $OpenBSD: isakmp_doi.c,v 1.22 2004/06/20 17:17:35 ho Exp $ */
+/* $EOM: isakmp_doi.c,v 1.42 2000/09/12 16:29:41 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * XXX This DOI is very fuzzily defined, and should perhaps be short-circuited
+ * to the IPsec DOI instead. At the moment I will have it as its own DOI,
+ * as the ISAKMP architecture seems to imply it should be done like this.
+ */
+
+#include <sys/types.h>
+
+#include "sysdep.h"
+
+#include "doi.h"
+#include "exchange.h"
+#include "isakmp.h"
+#include "isakmp_doi.h"
+#include "ipsec.h"
+#include "log.h"
+#include "message.h"
+#include "sa.h"
+#include "util.h"
+
+#ifdef USE_DEBUG
+static int isakmp_debug_attribute(u_int16_t, u_int8_t *, u_int16_t,
+ void *);
+#endif
+static void isakmp_finalize_exchange(struct message *);
+static struct keystate *isakmp_get_keystate(struct message *);
+static int isakmp_initiator(struct message *);
+static int isakmp_responder(struct message *);
+static void isakmp_setup_situation(u_int8_t *);
+static size_t isakmp_situation_size(void);
+static u_int8_t isakmp_spi_size(u_int8_t);
+static int isakmp_validate_attribute(u_int16_t, u_int8_t *, u_int16_t,
+ void *);
+static int isakmp_validate_exchange(u_int8_t);
+static int isakmp_validate_id_information(u_int8_t, u_int8_t *,
+ u_int8_t *, size_t, struct exchange *);
+static int isakmp_validate_key_information(u_int8_t *, size_t);
+static int isakmp_validate_notification(u_int16_t);
+static int isakmp_validate_proto(u_int8_t);
+static int isakmp_validate_situation(u_int8_t *, size_t *, size_t);
+static int isakmp_validate_transform_id(u_int8_t, u_int8_t);
+
+static struct doi isakmp_doi = {
+ {0}, ISAKMP_DOI_ISAKMP, 0, 0, 0,
+#ifdef USE_DEBUG
+ isakmp_debug_attribute,
+#endif
+ 0, /* delete_spi not needed. */
+ 0, /* exchange_script not needed. */
+ isakmp_finalize_exchange,
+ 0, /* free_exchange_data not needed. */
+ 0, /* free_proto_data not needed. */
+ 0, /* free_sa_data not needed. */
+ isakmp_get_keystate,
+ 0, /* get_spi not needed. */
+ 0, /* handle_leftover_payload not needed. */
+ 0, /* informational_post_hook not needed. */
+ 0, /* informational_pre_hook not needed. */
+ 0, /* XXX need maybe be filled-in. */
+ 0, /* proto_init not needed. */
+ isakmp_setup_situation,
+ isakmp_situation_size,
+ isakmp_spi_size,
+ isakmp_validate_attribute,
+ isakmp_validate_exchange,
+ isakmp_validate_id_information,
+ isakmp_validate_key_information,
+ isakmp_validate_notification,
+ isakmp_validate_proto,
+ isakmp_validate_situation,
+ isakmp_validate_transform_id,
+ isakmp_initiator,
+ isakmp_responder,
+#ifdef USE_DEBUG
+ ipsec_decode_ids
+#endif
+};
+
+/* Requires doi_init to already have been called. */
+void
+isakmp_doi_init(void)
+{
+ doi_register(&isakmp_doi);
+}
+
+#ifdef USE_DEBUG
+int
+isakmp_debug_attribute(u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vmsg)
+{
+ /* XXX Not implemented yet. */
+ return 0;
+}
+#endif /* USE_DEBUG */
+
+static void
+isakmp_finalize_exchange(struct message *msg)
+{
+}
+
+static struct keystate *
+isakmp_get_keystate(struct message *msg)
+{
+ return 0;
+}
+
+static void
+isakmp_setup_situation(u_int8_t *buf)
+{
+ /* Nothing to do. */
+}
+
+static size_t
+isakmp_situation_size(void)
+{
+ return 0;
+}
+
+static u_int8_t
+isakmp_spi_size(u_int8_t proto)
+{
+ /* One way to specify ISAKMP SPIs is to say they're zero-sized. */
+ return 0;
+}
+
+static int
+isakmp_validate_attribute(u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vmsg)
+{
+ /* XXX Not implemented yet. */
+ return -1;
+}
+
+static int
+isakmp_validate_exchange(u_int8_t exch)
+{
+ /* If we get here the exchange is invalid. */
+ return -1;
+}
+
+static int
+isakmp_validate_id_information(u_int8_t type, u_int8_t *extra, u_int8_t *buf,
+ size_t sz, struct exchange *exchange)
+{
+ return zero_test(extra, ISAKMP_ID_DOI_DATA_LEN);
+}
+
+static int
+isakmp_validate_key_information(u_int8_t *buf, size_t sz)
+{
+ /* Nothing to do. */
+ return 0;
+}
+
+static int
+isakmp_validate_notification(u_int16_t type)
+{
+ /* If we get here the message type is invalid. */
+ return -1;
+}
+
+static int
+isakmp_validate_proto(u_int8_t proto)
+{
+ /* If we get here the protocol is invalid. */
+ return -1;
+}
+
+static int
+isakmp_validate_situation(u_int8_t *buf, size_t *sz, size_t len)
+{
+ /* There are no situations in the ISAKMP DOI. */
+ *sz = 0;
+ return 0;
+}
+
+static int
+isakmp_validate_transform_id(u_int8_t proto, u_int8_t transform_id)
+{
+ /* XXX Not yet implemented. */
+ return -1;
+}
+
+static int
+isakmp_initiator(struct message *msg)
+{
+ if (msg->exchange->type != ISAKMP_EXCH_INFO) {
+ log_print("isakmp_initiator: unsupported exchange type %d "
+ "in phase %d", msg->exchange->type, msg->exchange->phase);
+ return -1;
+ }
+ return message_send_info(msg);
+}
+
+static int
+isakmp_responder(struct message *msg)
+{
+ struct payload *p;
+
+ switch (msg->exchange->type) {
+ case ISAKMP_EXCH_INFO:
+ for (p = payload_first(msg, ISAKMP_PAYLOAD_NOTIFY); p;
+ p = TAILQ_NEXT(p, link)) {
+ LOG_DBG((LOG_EXCHANGE, 10, "isakmp_responder: "
+ "got NOTIFY of type %s, ignoring",
+ constant_name(isakmp_notify_cst,
+ GET_ISAKMP_NOTIFY_MSG_TYPE(p->p))));
+ p->flags |= PL_MARK;
+ }
+
+ for (p = payload_first(msg, ISAKMP_PAYLOAD_DELETE); p;
+ p = TAILQ_NEXT(p, link)) {
+ LOG_DBG((LOG_EXCHANGE, 10,
+ "isakmp_responder: got DELETE, ignoring"));
+ p->flags |= PL_MARK;
+ }
+ return 0;
+
+#ifdef USE_ISAKMP_CFG
+ case ISAKMP_EXCH_TRANSACTION:
+ /* return 0 isakmp_cfg_responder (msg); */
+#endif /* USE_ISAKMP_CFG */
+
+ default:
+ /* XXX So far we don't accept any proposals. */
+ if (payload_first(msg, ISAKMP_PAYLOAD_SA)) {
+ message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN,
+ 0, 1, 0);
+ return -1;
+ }
+ }
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/isakmp_doi.h b/keyexchange/isakmpd-20041012/isakmp_doi.h
new file mode 100644
index 0000000..13a485b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmp_doi.h
@@ -0,0 +1,37 @@
+/* $OpenBSD: isakmp_doi.h,v 1.5 2004/04/15 18:39:26 deraadt Exp $ */
+/* $EOM: isakmp_doi.h,v 1.1 1998/07/07 23:20:29 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _ISAKMP_DOI_H_
+#define _ISAKMP_DOI_H_
+
+extern void isakmp_doi_init(void);
+
+#endif /* _ISAKMP_DOI_H_ */
diff --git a/keyexchange/isakmpd-20041012/isakmp_fld.fld b/keyexchange/isakmpd-20041012/isakmp_fld.fld
new file mode 100644
index 0000000..05eeda9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmp_fld.fld
@@ -0,0 +1,164 @@
+# $OpenBSD: isakmp_fld.fld,v 1.8 2004/06/20 15:24:05 ho Exp $
+# $EOM: isakmp_fld.fld,v 1.5 1999/04/25 13:38:22 niklas Exp $
+
+#
+# Copyright (c) 1998, 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# XXX There are num-declared fields below that really are csts.
+
+# The ISAKMP message header.
+ISAKMP_HDR
+# XXX I want a way to specify COOKIES as an overlay of ICOOKIE + RCOOKIE
+ ICOOKIE raw 8
+ RCOOKIE raw 8
+ NEXT_PAYLOAD cst 1 isakmp_payload_cst
+ VERSION num 1
+ EXCH_TYPE cst 1 ike_exch_cst,isakmp_exch_cst
+ FLAGS mask 1 isakmp_flags_cst
+ MESSAGE_ID raw 4
+ LENGTH num 4
+.
+
+# Generic payload header.
+ISAKMP_GEN
+ NEXT_PAYLOAD cst 1 isakmp_payload_cst
+ RESERVED ign 1
+ LENGTH num 2
+.
+
+# ISAKMP data attributes
+ISAKMP_ATTR
+ TYPE num 2 ike_attr_cst,ipsec_attr_cst
+ LENGTH_VALUE num 2
+ VALUE raw
+.
+
+# Security association payload.
+ISAKMP_SA : ISAKMP_GEN
+ DOI num 4 isakmp_doi_cst,ipsec_doi_cst
+ SIT raw
+.
+
+# Proposal payload.
+ISAKMP_PROP : ISAKMP_GEN
+ NO num 1
+ PROTO cst 1 isakmp_proto_cst,ipsec_proto_cst
+ SPI_SZ num 1
+ NTRANSFORMS num 1
+ SPI raw
+.
+
+# Transform payload.
+ISAKMP_TRANSFORM : ISAKMP_GEN
+ NO num 1
+ ID num 1
+ RESERVED ign 2
+ SA_ATTRS raw
+.
+
+# Key exchange payload.
+ISAKMP_KE : ISAKMP_GEN
+ DATA raw
+.
+
+# Identification payload.
+ISAKMP_ID : ISAKMP_GEN
+ TYPE num 1
+ DOI_DATA raw 3
+ DATA raw
+.
+
+# Certificate payload.
+ISAKMP_CERT : ISAKMP_GEN
+ ENCODING cst 1 isakmp_certenc_cst
+ DATA raw
+.
+
+# Certificate request payload.
+ISAKMP_CERTREQ : ISAKMP_GEN
+ TYPE cst 1 isakmp_certenc_cst
+ AUTHORITY raw
+.
+
+# Hash payload.
+ISAKMP_HASH : ISAKMP_GEN
+ DATA raw
+.
+
+# Signature payload.
+ISAKMP_SIG : ISAKMP_GEN
+ DATA raw
+.
+
+# Nonce payload.
+ISAKMP_NONCE : ISAKMP_GEN
+ DATA raw
+.
+
+# Notify payload.
+ISAKMP_NOTIFY : ISAKMP_GEN
+ DOI cst 4 isakmp_doi_cst,ipsec_doi_cst
+ PROTO cst 1 isakmp_proto_cst
+ SPI_SZ num 1
+ MSG_TYPE cst 2 isakmp_notify_cst,ipsec_notify_cst
+ SPI raw
+.
+
+# Delete payload.
+ISAKMP_DELETE : ISAKMP_GEN
+ DOI cst 4 isakmp_doi_cst,ipsec_doi_cst
+ PROTO cst 1 isakmp_proto_cst
+ SPI_SZ num 1
+ NSPIS num 2
+ SPI raw
+.
+
+# Vendor ID payload.
+ISAKMP_VENDOR : ISAKMP_GEN
+ ID raw
+.
+
+# Attribute payload.
+ISAKMP_ATTRIBUTE : ISAKMP_GEN
+ TYPE num 1 isakmp_cfg_cst
+ RESERVED ign 1
+ ID num 2
+ ATTRS raw
+.
+
+# NAT Discovery payload.
+ISAKMP_NAT_D : ISAKMP_GEN
+ DATA raw
+.
+
+# NAT Original Address payload.
+ISAKMP_NAT_OA : ISAKMP_GEN
+ TYPE num 1
+ RESERVED ign 3
+ DATA raw
+.
diff --git a/keyexchange/isakmpd-20041012/isakmp_num.cst b/keyexchange/isakmpd-20041012/isakmp_num.cst
new file mode 100644
index 0000000..d96d923
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmp_num.cst
@@ -0,0 +1,264 @@
+# $OpenBSD: isakmp_num.cst,v 1.10 2004/08/10 15:59:10 ho Exp $
+# $EOM: isakmp_num.cst,v 1.3 2000/05/17 03:09:50 angelos Exp $
+
+#
+# Copyright (c) 1998, 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# XXX Please fill in references to the drafts, chapter & verse for each
+# constant group below.
+# Also think about ranges, can they be specified differently? Can we use
+# these constants for validity checks?
+
+# ISAKMP payload type.
+ISAKMP_PAYLOAD
+ NONE 0
+ SA 1
+ PROPOSAL 2
+ TRANSFORM 3
+ KEY_EXCH 4
+ ID 5
+ CERT 6
+ CERT_REQ 7
+ HASH 8
+ SIG 9
+ NONCE 10
+ NOTIFY 11
+ DELETE 12
+ VENDOR 13
+# XXX the following are not quite legitimate according to the IETF process
+ ATTRIBUTE 14 # IKE Mode-Config attribute
+ SAK 15 # RFC 3547, SA KEK Payload
+ SAT 16 # RFC 3547, SA TEK Payload
+ KD 17 # RFC 3547, Key Download
+ SEQ 18 # RFC 3547, Sequence Number
+ POP 19 # RFC 3547, Proof of possession
+ NAT_D 20 # RFC 3947, NAT Discovery payload
+ NAT_OA 21 # RFC 3947, NAT Original Address payload
+ RESERVED_MIN 22
+ RESERVED_MAX 127
+ PRIVATE_MIN 128
+# XXX values from draft-ietf-ipsec-nat-t-ike-01,02,03. Later drafts specify
+# XXX NAT_D as payload 15 and NAT_OA as 16, but these are allocated by RFC
+# XXX 3547 as seen above.
+ NAT_D_DRAFT 130 # NAT Discovery payload
+ NAT_OA_DRAFT 131 # NAT Original Address payload
+ PRIVATE_MAX 255
+ MAX 255
+.
+
+# ISAKMP exchange types.
+ISAKMP_EXCH
+ NONE 0
+ BASE 1
+ ID_PROT 2
+ AUTH_ONLY 3
+ AGGRESSIVE 4
+ INFO 5
+# XXX the following are not quite legitimate according to the IETF process
+ TRANSACTION 6
+ FUTURE_MIN 7
+ FUTURE_MAX 31
+ DOI_MIN 32
+ DOI_MAX 255
+.
+
+# ISAKMP flags.
+ISAKMP_FLAGS
+ ENC 1
+ COMMIT 2
+ AUTH_ONLY 4
+.
+
+# ISAKMP certificate encoding.
+ISAKMP_CERTENC
+ NONE 0
+ PKCS 1
+ PGP 2
+ DNS 3
+ X509_SIG 4
+ X509_KE 5
+ KERBEROS 6
+ CRL 7
+ ARL 8
+ SPKI 9
+ X509_ATTR 10
+ KEYNOTE 11
+ HASH_URL_PKIX_CERT 12
+ HASH_URL_PKIX_BUNDLE 13
+ RESERVED_MIN 14
+ RESERVED_MAX 255
+.
+
+# ISAKMP Notify message types.
+ISAKMP_NOTIFY
+ 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
+ RESERVED_MIN 31
+ RESERVED_MAX 8191
+ PRIVATE_MIN 8192
+ PRIVATE_MAX 16383
+ STATUS_CONNECTED 16384
+ STATUS_RESERVED1_MIN 16385
+ STATUS_RESERVED1_MAX 24575
+ STATUS_DOI_MIN 24576
+ STATUS_DOI_MAX 32767
+ STATUS_PRIVATE_MIN 32768
+ STATUS_DPD_R_U_THERE 36136
+ STATUS_DPD_R_U_THERE_ACK 36137
+ STATUS_PRIVATE_MAX 40959
+ STATUS_RESERVED2_MIN 40960
+ STATUS_RESERVED2_MAX 65535
+.
+
+# ISAKMP V2 Notify payload types
+ISAKMP_V2_NOTIFY
+ 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
+ AUTHENTICATION_FAILED 24
+ SINGLE_PAIR_REQUIRED 34
+ NO_ADDITIONAL_SAS 35
+ INTERNAL_ADDRESS_FAILURE 36
+ FAILED_CP_REQUIRED 37
+ TS_UNACCEPTABLE 38
+ RESERVED_MIN 39
+ RESERVED_MAX 8191
+ PRIVATE_MIN 8192
+ PRIVATE_MAX 16383
+ STATUS_RESERVED1_MIN 16384
+ STATUS_RESERVED1_MAX 24577
+ STATUS_INITIAL_CONTACT 24578
+ STATUS_SET_WINDOW_SIZE 24579
+ STATUS_ADDITIONAL_IS_POSSIBLE 24580
+ STATUS_IPCOMP_SUPPORTED 24581
+ STATUS_NAT_DETECTION_SOURCE_IP 24582
+ STATUS_NAT_DETECTION_DESTINATION_IP 24583
+ STATUS_COOKIE 24584
+ STATUS_USE_TRANSPORT_MODE 24585
+ STATUS_HTTP_CERT_LOOKUP_SUPPORTED 24586
+ STATUS_RESERVED2_MIN 24587
+ STATUS_RESERVED2_MAX 40959
+ STATUS_PRIVATE_MIN 40960
+ STATUS_PRIVATE_MAX 65535
+.
+
+# ISAKMP DOI Identifier.
+ISAKMP_DOI
+ ISAKMP 0
+.
+
+# ISAKMP Protocol ID.
+ISAKMP_PROTO
+ ISAKMP 1
+.
+
+# ISAKMP transaction message type.
+ISAKMP_CFG
+ REQUEST 1
+ REPLY 2
+ SET 3
+ ACK 4
+ FUTURE_MIN 5
+ FUTURE_MAX 127
+ PRIVATE_MIN 128
+ PRIVATE_MAX 255
+.
+
+# ISAKMP configuration attributes.
+ISAKMP_CFG_ATTR
+ 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_NETMASK 9
+ INTERNAL_IP6_DNS 10
+ INTERNAL_IP6_NBNS 11
+ INTERNAL_IP6_DHCP 12
+ INTERNAL_IP4_SUBNET 13
+ SUPPORTED_ATTRIBUTES 14
+ INTERNAL_IP6_SUBNET 15
+ FUTURE_MIN 16
+ FUTURE_MAX 16383
+ PRIVATE_MIN 16384
+ PRIVATE_MAX 32767
+.
+
+# ISAKMP EAP
+ISAKMP_EAP_CODE
+ REQUEST 1
+ RESPONSE 2
+ SUCCESS 3
+ FAILURE 4
+.
+
+# ISAKMP EAP Types (RFC2284)
+ISAKMP_EAP_TYPE
+ IDENTITY 1
+ NOTIFICATION 2
+ NAK 3 # Response only
+ MD5_CHALLENGE 4
+ OTP 5
+ TOKEN 6 # Generic token card
+.
+
diff --git a/keyexchange/isakmpd-20041012/isakmpd.8 b/keyexchange/isakmpd-20041012/isakmpd.8
new file mode 100644
index 0000000..e7f6987
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmpd.8
@@ -0,0 +1,603 @@
+.\" $OpenBSD: isakmpd.8,v 1.65 2004/07/08 10:37:12 jmc Exp $
+.\" $EOM: isakmpd.8,v 1.23 2000/05/02 00:30:23 niklas Exp $
+.\"
+.\" Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist.
+.\" All rights reserved.
+.\" Copyright (c) 1999 Angelos D. Keromytis. All rights reserved.
+.\" Copyright (c) 2001, 2002 Håkan Olsson. 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+.\"
+.\" Manual page, using -mandoc macros
+.\"
+.Dd August 07, 2002
+.Dt ISAKMPD 8
+.Os
+.Sh NAME
+.Nm isakmpd
+.Nd ISAKMP/Oakley a.k.a. IKE key management daemon
+.Sh SYNOPSIS
+.Nm isakmpd
+.Bk -words
+.Op Fl 4
+.Op Fl 6
+.Op Fl c Ar config-file
+.Op Fl a
+.Op Fl d
+.Op Fl D Ar class=level
+.Op Fl f Ar fifo
+.Op Fl i Ar pid-file
+.Op Fl n
+.Op Fl p Ar listen-port
+.Op Fl P Ar local-port
+.Op Fl K
+.Op Fl L
+.Op Fl l Ar packetlog-file
+.Op Fl r Ar seed
+.Op Fl R Ar report-file
+.Op Fl v
+.Ek
+.Sh DESCRIPTION
+The
+.Nm
+daemon establishes security associations for encrypted
+and/or authenticated network traffic.
+At this moment, and probably forever, this means
+.Xr ipsec 4
+traffic.
+.Pp
+The way
+.Nm
+goes about its work is by maintaining an internal configuration
+as well as a policy database which describes what kinds of SAs to negotiate,
+and by listening for different events that trigger these negotiations.
+The events that control
+.Nm
+consist of negotiation initiations from a remote party, user input via
+a FIFO or by signals, upcalls from the kernel via a
+.Dv PF_KEY
+socket, and lastly by scheduled events triggered by timers running out.
+.Pp
+Most uses of
+.Nm
+will be to implement so called "virtual private
+networks" or VPNs for short.
+The
+.Xr vpn 8
+manual page describes how to set up
+.Nm
+for a simple VPN.
+For other uses, some more knowledge of IKE as a protocol is required.
+One source of information are the RFCs mentioned below.
+.Pp
+On startup
+.Nm
+forks into two processes for privilege separation.
+The unprivileged child jails itself with
+.Xr chroot 8
+to
+.Pa /var/empty .
+The privileged process communicates with the child, reads configuration files
+and PKI information and binds to privileged ports on its behalf.
+See
+.Sx CAVEATS
+section below.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl 4 | Fl 6
+These options control what address family
+.Pf ( Dv AF_INET
+and/or
+.Dv AF_INET6 )
+.Nm
+will use.
+The default is to use both IPv4 and IPv6.
+.It Fl a
+If given,
+.Nm
+does not set up flows automatically.
+This is useful when flows are configured with
+.Xr ipsecadm 4
+or by other programs like
+.Xr bgpd 8 .
+Thus
+.Nm
+only takes care of the SA establishment.
+.It Fl c Ar config-file
+If given, the
+.Fl c
+option specifies an alternate configuration file instead of
+.Pa /etc/isakmpd/isakmpd.conf .
+As this file may contain sensitive information, it must be readable
+only by the user running the daemon.
+.Nm
+will reread the configuration file when sent a
+.Dv SIGHUP
+signal.
+.It Fl d
+The
+.Fl d
+option is used to make the daemon run in the foreground, logging to stderr.
+.It Xo Fl D
+.Ar class Ns = Ns Ar level
+.Xc
+Debugging class.
+It's possible to specify this argument many times.
+It takes a parameter of the form
+.Ar class Ns = Ns Ar level ,
+where both
+.Ar class
+and
+.Ar level
+are numbers.
+.Ar class
+denotes a debugging class, and
+.Ar level
+the level you want that debugging class to
+limit debug printouts at (i.e., all debug printouts above the level specified
+will not output anything).
+If
+.Ar class
+is set to
+.Sq A ,
+then all debugging classes are set to the specified level.
+.Pp
+Valid values for
+.Ar class
+are as follows:
+.Pp
+.Bl -tag -width 2n -compact -offset indent
+.It 0
+Misc
+.It 1
+Transport
+.It 2
+Message
+.It 3
+Crypto
+.It 4
+Timer
+.It 5
+Sysdep
+.It 6
+SA
+.It 7
+Exchange
+.It 8
+Negotiation
+.It 9
+Policy
+.It 10
+FIFO user interface
+.It A
+All
+.El
+.Pp
+Currently used values for
+.Ar level
+are 0 to 99.
+.It Fl f Ar fifo
+The
+.Fl f
+option specifies the
+.Tn FIFO
+(a.k.a. named pipe) where the daemon listens for
+user requests.
+If the path given is a dash
+.Pq Sq \&- ,
+.Nm
+will listen to stdin instead.
+.It Fl i Ar pid-file
+By default the PID of the daemon process will be written to
+.Pa /var/run/isakmpd.pid .
+This path can be overridden by specifying another one as the argument to the
+.Fl i
+option.
+.It Fl n
+When the
+.Fl n
+option is given, the kernel will not take part in the negotiations.
+This is a non-destructive mode, so to speak, in that it won't alter any
+SAs in the IPsec stack.
+.It Fl p Ar listen-port
+The
+.Fl p
+option specifies the listen port the daemon will bind to.
+.It Fl P Ar local-port
+On the other hand, the port specified to capital
+.Fl P
+will be what the daemon binds its local end to when acting as
+initiator.
+.It Fl K
+When this option is given,
+.Nm
+does not read the policy configuration file and no
+.Xr keynote 4
+policy check is accomplished.
+This option can be used when policies for flows and SA establishment are
+arranged by other programs like
+.Xr ipsecadm 8
+or
+.Xr bgpd 8 .
+.It Fl L
+Enable IKE packet capture.
+When this option is given,
+.Nm
+will capture to file an unencrypted copy of the negotiation packets it
+is sending and receiving.
+This file can later be read by
+.Xr tcpdump 8
+and other utilities using
+.Xr pcap 3 .
+.It Fl l Ar packetlog-file
+As option
+.Fl L
+above, but capture to a specified file.
+.It Fl r Ar seed
+If given, a deterministic random number sequence will be used internally.
+This is useful for setting up regression tests.
+.It Fl R Ar report-file
+When you signal
+.Nm
+a
+.Dv SIGUSR1 ,
+it will report its internal state to a report file, normally
+.Pa /var/run/isakmpd.report ,
+but this can be changed by feeding
+the file name as an argument to the
+.Fl R
+flag.
+.It Fl v
+Enables verbose logging.
+Normally,
+.Nm
+is silent and outputs only messages when a warning or an error occurs.
+With verbose logging
+.Nm
+reports successful completion of phase 1 (Main and Aggressive) and phase 2
+(Quick) exchanges (Information and Transaction exchanges do not generate any
+additional status information).
+.El
+.Ss Setting up an IKE public key infrastructure (a.k.a. PKI)
+In order to use public key based authentication, there has to be an
+infrastructure managing the key signing.
+Either there is an already existing PKI
+.Nm
+should take part in, or there will be a need to set one up.
+In the former case, what is needed to be done varies depending on the
+actual Certificate Authority used, and is therefore not covered here,
+other than mentioning that
+.Xr openssl 1
+needs to be used to create a certificate signing request that the
+CA understands.
+The latter case, however, is described here:
+.Bl -enum
+.It
+Create your own CA as root.
+.Bd -literal
+# openssl genrsa -out /etc/ssl/private/ca.key 1024
+# openssl req -new -key /etc/ssl/private/ca.key \e
+ -out /etc/ssl/private/ca.csr
+.Ed
+.Pp
+You are then asked to enter information that will be incorporated
+into your certificate request.
+What you are about to enter is what is called a Distinguished Name (DN).
+There are quite a few fields but you can leave some blank.
+For some fields there will be a default value; if you enter
+.Sq \&. ,
+the field will be left blank.
+.Bd -literal
+# openssl x509 -req -days 365 -in /etc/ssl/private/ca.csr \e
+ -signkey /etc/ssl/private/ca.key \e
+ -extfile /etc/ssl/x509v3.cnf -extensions x509v3_CA \e
+ -out /etc/ssl/ca.crt
+.Ed
+.Pp
+.It
+Create keys and certificates for your IKE peers.
+This step as well as the next one, needs to be done for every peer.
+Furthermore the last step will need to be done once for each ID you
+want the peer to have.
+The 10.0.0.1 below symbolizes that ID, in this case an IPv4 ID,
+and should be changed for each invocation.
+You will be asked for a DN for each run.
+Encoding the ID in the common name is recommended, as it should be unique.
+.Bd -literal
+# openssl genrsa -out /etc/isakmpd/private/local.key 1024
+# openssl req -new -key /etc/isakmpd/private/local.key \e
+ -out /etc/isakmpd/private/10.0.0.1.csr
+.Ed
+.Pp
+Now take these certificate signing requests to your CA and process
+them like below.
+You have to add a subjectAltName extension field
+to the certificate in order to make it usable by
+.Nm isakmpd .
+There are two possible ways to add the extensions to the certificate.
+Either you have to run
+.Xr certpatch 8
+or you have to make use of an OpenSSL configuration file, for example
+.Pa /etc/ssl/x509v3.cnf .
+Replace 10.0.0.1 with the IP-address which
+.Nm
+will use as the certificate identity.
+.Pp
+To use
+.Xr certpatch 8 ,
+do the following
+.Bd -literal
+# openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \e
+ -CAkey /etc/ssl/private/ca.key -CAcreateserial \e
+ -out 10.0.0.1.crt
+# certpatch -i 10.0.0.1 -k /etc/ssl/private/ca.key \e
+ 10.0.0.1.crt 10.0.0.1.crt
+.Ed
+.Pp
+Otherwise do
+.Bd -literal
+# setenv CERTIP 10.0.0.1
+# openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \e
+ -CAkey /etc/ssl/private/ca.key -CAcreateserial \e
+ -extfile /etc/ssl/x509v3.cnf -extensions x509v3_IPAddr \e
+ -out 10.0.0.1.crt
+.Ed
+.Pp
+For a FQDN certificate, do
+.Bd -literal
+# setenv CERTFQDN somehost.somedomain
+# openssl x509 -req -days 365 -in somehost.somedomain.csr \e
+ -CA /etc/ssl/ca.crt -CAkey /etc/ssl/private/ca.key \e
+ -CAcreateserial \e
+ -extfile /etc/ssl/x509v3.cnf -extensions x509v3_FQDN \e
+ -out somehost.somedomain.crt
+.Ed
+.Pp
+or with
+.Xr certpatch 8
+.Bd -literal
+# certpatch -t fqdn -i somehost.somedomain \e
+ -k /etc/ssl/private/ca.key \e
+ somehost.somedomain.crt somehost.somedomain.crt
+.Ed
+.Pp
+(This assumes the previous steps were used to create a request for
+somehost.somedomain instead of 10.0.0.1)
+.Pp
+Put the certificate (the file ending in .crt) in
+.Pa /etc/isakmpd/certs/
+on your local system.
+Also carry over the CA cert
+.Pa /etc/ssl/ca.crt
+and put it in
+.Pa /etc/isakmpd/ca/ .
+.El
+.Pp
+To revoke certificates, create a Certificate Revocation List (CRL) file
+and install it in the
+.Pa /etc/isakmpd/crls/
+directory.
+See
+.Xr openssl 1
+and the
+.Sq crl
+subcommand for more info.
+.Pp
+It is also possible to store trusted public keys to make them directly
+usable by
+.Nm isakmpd .
+The keys should be saved in PEM format (see
+.Xr openssl 1 )
+and named and stored after this easy formula:
+.Bl -tag -width for_ufqdn_identities
+.It For IPv4 identities
+/etc/isakmpd/pubkeys/ipv4/A.B.C.D
+.It For IPv6 identities
+/etc/isakmpd/pubkeys/ipv6/abcd:abcd::ab:bc
+.It For FQDN identities
+/etc/isakmpd/pubkeys/fqdn/foo.bar.org
+.It For UFQDN identities
+/etc/isakmpd/pubkeys/ufqdn/user@foo.bar.org
+.El
+.Ss The FIFO user interface
+When
+.Nm
+starts, it creates a FIFO (named pipe) where it listens for user
+requests.
+All commands start with a single letter, followed by command-specific options.
+Available commands are:
+.Bl -tag -width Ds -compact
+.Pp
+.It Ic "c <name>"
+Start the named connection, if stopped or inactive.
+.Pp
+.It Ic "C set [section]:tag=value"
+.It Ic "C set [section]:tag=value force"
+.It Ic "C add [section]:tag=value"
+.It Ic "C rm [section]:tag"
+.It Ic "C rms [section]"
+Update the running
+.Nm
+configuration atomically.
+.Sq set
+sets a configuration value consisting of a section, tag and value triplet.
+.Sq set
+will fail if the configuration already contains a section with the named tag;
+use the
+.Sq force
+option to change this behaviour.
+.Sq add
+appends a configuration value to the named configuration list tag.
+.Sq rm
+removes a tag in a section.
+.Sq rms
+removes an entire section.
+.Pp
+NOTE: Sending isakmpd a SIGHUP or an "R" through the FIFO will
+void any updates done to the configuration.
+.Pp
+.It Ic "C get [section]:tag"
+Get the configuration value of the specified section and tag.
+The result is stored in
+.Pa /var/run/isakmpd.result .
+.Pp
+.It Ic "d <cookies> <msgid>"
+Delete the specified SA from the system.
+Specify <msgid> as "-" to match a Phase 1 SA.
+.Pp
+.It Ic "D <class> <level>"
+.It Ic "D A <level>"
+.It Ic "D T"
+Set debug class <class> to level <level>.
+If <class> is specified as "A", the level applies to all debug classes.
+"D T" toggles all debug classes to level zero.
+Another "D T" command will toggle them back to the earlier levels.
+.Pp
+.It Ic "p on[=<path>]"
+.It Ic "p off"
+Enable or disable cleartext IKE packet capture.
+When enabling, optionally specify which file
+.Nm
+should capture the packets to.
+.Pp
+.It Ic "Q"
+Cleanly shutdown the daemon, as when sent a
+.Dv SIGTERM
+signal.
+.Pp
+.It Ic "r"
+Report
+.Nm
+internal state to a file.
+See
+.Fl R
+option.
+Same as when sent a
+.Dv SIGUSR1
+signal.
+.Pp
+.It Ic "R"
+Reinitialize
+.Nm isakmpd ,
+as when sent a
+.Dv SIGHUP
+signal.
+.Pp
+.It Ic "S"
+Report information on all known SAs to the
+.Pa /var/run/isakmpd.result
+file.
+.Pp
+.It Ic "t <name>"
+Tear down the named connection, if active.
+.Pp
+.It Ic "T"
+Tear down all active connections.
+.El
+.Sh FILES
+.Bl -tag -width /etc/isakmpd/private/local.
+.It Pa /etc/isakmpd/ca/
+The directory where CA certificates can be found.
+.It Pa /etc/isakmpd/certs/
+The directory where IKE certificates can be found, both the local
+certificate(s) and those of the peers, if a choice to have them kept
+permanently has been made.
+.It Pa /etc/isakmpd/crls/
+The directory where CRLs can be found.
+.It Pa /etc/isakmpd/isakmpd.conf
+The configuration file.
+As this file can contain sensitive information
+it must not be readable by anyone but the user running
+.Nm isakmpd .
+.It Pa /etc/isakmpd/isakmpd.policy
+The keynote policy configuration file.
+The same mode requirements as
+.Nm isakmpd.conf .
+.It Pa /etc/isakmpd/private/local.key
+A local private key for certificate based authentication.
+There has to be a certificate for this key in the certificate directory
+mentioned above.
+The same mode requirements as
+.Nm isakmpd.conf .
+.It Pa /etc/isakmpd/pubkeys/
+Directory in which trusted public keys can be kept.
+The keys must be named in the fashion described above.
+.It Pa /var/run/isakmpd.pid
+The PID of the current daemon.
+.It Pa /var/run/isakmpd.fifo
+The FIFO used to manually control
+.Nm isakmpd .
+.It Pa /var/run/isakmpd.pcap
+The default IKE packet capture file.
+.It Pa /var/run/isakmpd.report
+The report file written when
+.Dv SIGUSR1
+is received.
+.It Pa /var/run/isakmpd.result
+The report file written when the
+.Sq S
+or
+.Sq "C get"
+command is issued in the command FIFO.
+.It Pa /usr/share/ipsec/isakmpd/
+A directory containing some sample
+.Nm
+and keynote policy configuration files.
+.El
+.Sh SEE ALSO
+.Xr openssl 1 ,
+.Xr getnameinfo 3 ,
+.Xr pcap 3 ,
+.Xr ipsec 4 ,
+.Xr isakmpd.conf 5 ,
+.Xr isakmpd.policy 5 ,
+.Xr ssl 8 ,
+.Xr tcpdump 8 ,
+.Xr vpn 8
+.Sh HISTORY
+The ISAKMP/Oakley key management protocol is described in the RFCs
+.%T RFC 2407 ,
+.%T RFC 2408
+and
+.%T RFC 2409 .
+This implementation was done 1998 by Niklas Hallqvist and Niels Provos,
+sponsored by Ericsson Radio Systems.
+.Sh CAVEATS
+When storing a trusted public key for an IPv6 identity, the
+.Em most efficient
+form of address representation, i.e "::" instead of ":0:0:0:",
+must be used or the matching will fail.
+.Nm
+uses the output from
+.Xr getnameinfo 3
+for the address-to-name translation.
+The privileged process only allows binding to the default port 500 or
+unprivileged ports (>1024).
+It is not possible to change the interfaces
+.Nm
+listens on without a restart.
+.Sh BUGS
+The
+.Fl P
+flag does not do what we document, rather it does nothing.
diff --git a/keyexchange/isakmpd-20041012/isakmpd.c b/keyexchange/isakmpd-20041012/isakmpd.c
new file mode 100644
index 0000000..8675201
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmpd.c
@@ -0,0 +1,543 @@
+/* $OpenBSD: isakmpd.c,v 1.68 2004/09/17 14:54:09 hshoexer Exp $ */
+/* $EOM: isakmpd.c,v 1.54 2000/10/05 09:28:22 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "sysdep.h"
+
+#include "app.h"
+#include "conf.h"
+#include "connection.h"
+#include "init.h"
+#include "libcrypto.h"
+#include "log.h"
+#include "monitor.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "udp.h"
+#include "ui.h"
+#include "util.h"
+#include "cert.h"
+
+#ifdef USE_POLICY
+#include "policy.h"
+#endif
+
+static void usage(void);
+
+/*
+ * Set if -d is given, currently just for running in the foreground and log
+ * to stderr instead of syslog.
+ */
+int debug = 0;
+
+/* Set when no policy file is found. */
+int acquire_only = 0;
+
+/*
+ * If we receive a SIGHUP signal, this flag gets set to show we need to
+ * reconfigure ASAP.
+ */
+volatile sig_atomic_t sighupped = 0;
+
+/*
+ * If we receive a USR1 signal, this flag gets set to show we need to dump
+ * a report over our internal state ASAP. The file to report to is settable
+ * via the -R parameter.
+ */
+volatile sig_atomic_t sigusr1ed = 0;
+static char *report_file = "/var/run/isakmpd.report";
+
+/*
+ * If we receive a USR2 signal, this flag gets set to show we need to
+ * rehash our SA soft expiration timers to a uniform distribution.
+ * XXX Perhaps this is a really bad idea?
+ */
+volatile sig_atomic_t sigusr2ed = 0;
+
+/*
+ * If we receive a TERM signal, perform a "clean shutdown" of the daemon.
+ * This includes to send DELETE notifications for all our active SAs.
+ * Also on recv of an INT signal (Ctrl-C out of an '-d' session, typically).
+ */
+volatile sig_atomic_t sigtermed = 0;
+void daemon_shutdown_now(int);
+
+/* The default path of the PID file. */
+static char *pid_file = "/var/run/isakmpd.pid";
+
+#ifdef USE_DEBUG
+/* The path of the IKE packet capture log file. */
+static char *pcap_file = 0;
+#endif
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-4] [-6] [-a] [-c config-file] [-d] [-D class=level]\n"
+ " [-f fifo] [-i pid-file] [-K] [-n] [-p listen-port]\n"
+ " [-P local-port] [-L] [-l packetlog-file] [-r seed]\n"
+ " [-R report-file] [-v]\n",
+ sysdep_progname());
+ exit(1);
+}
+
+static void
+parse_args(int argc, char *argv[])
+{
+ int ch;
+ char *ep;
+#ifdef USE_DEBUG
+ int cls, level;
+ int do_packetlog = 0;
+#endif
+
+ while ((ch = getopt(argc, argv, "46ac:dD:f:i:Knp:P:Ll:r:R:v")) != -1) {
+ switch (ch) {
+ case '4':
+ bind_family |= BIND_FAMILY_INET4;
+ break;
+
+ case '6':
+ bind_family |= BIND_FAMILY_INET6;
+ break;
+
+ case 'a':
+ acquire_only++;
+ break;
+
+ case 'c':
+ conf_path = optarg;
+ break;
+
+ case 'd':
+ debug++;
+ break;
+
+#ifdef USE_DEBUG
+ case 'D':
+ if (sscanf(optarg, "%d=%d", &cls, &level) != 2) {
+ if (sscanf(optarg, "A=%d", &level) == 1) {
+ for (cls = 0; cls < LOG_ENDCLASS;
+ cls++)
+ log_debug_cmd(cls, level);
+ } else
+ log_print("parse_args: -D argument "
+ "unparseable: %s", optarg);
+ } else
+ log_debug_cmd(cls, level);
+ break;
+#endif /* USE_DEBUG */
+
+ case 'f':
+ ui_fifo = optarg;
+ break;
+
+ case 'i':
+ pid_file = optarg;
+ break;
+
+#ifdef USE_POLICY
+ case 'K':
+ ignore_policy++;
+ break;
+#endif
+
+ case 'n':
+ app_none++;
+ break;
+
+ case 'p':
+ udp_default_port = optarg;
+ break;
+
+ case 'P':
+ udp_bind_port = optarg;
+ break;
+
+#ifdef USE_DEBUG
+ case 'l':
+ pcap_file = optarg;
+ /* Fallthrough intended. */
+
+ case 'L':
+ do_packetlog++;
+ break;
+#endif /* USE_DEBUG */
+
+ case 'r':
+ seed = strtoul(optarg, &ep, 0);
+ srandom(seed);
+ if (*ep != '\0')
+ log_fatal("parse_args: invalid numeric arg "
+ "to -r (%s)", optarg);
+ regrand = 1;
+ break;
+
+ case 'R':
+ report_file = optarg;
+ break;
+
+ case 'v':
+ verbose_logging = 1;
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef USE_DEBUG
+ if (do_packetlog && !pcap_file)
+ pcap_file = PCAP_FILE_DEFAULT;
+#endif
+}
+
+static void
+sighup(int sig)
+{
+ sighupped = 1;
+}
+
+/* Report internal state on SIGUSR1. */
+static void
+report(void)
+{
+ FILE *rfp, *old;
+ mode_t old_umask;
+
+ old_umask = umask(S_IRWXG | S_IRWXO);
+ rfp = monitor_fopen(report_file, "w");
+ umask(old_umask);
+
+ if (!rfp) {
+ log_error("report: fopen (\"%s\", \"w\") failed", report_file);
+ return;
+ }
+ /* Divert the log channel to the report file during the report. */
+ old = log_current();
+ log_to(rfp);
+ ui_report("r");
+ log_to(old);
+ fclose(rfp);
+}
+
+static void
+sigusr1(int sig)
+{
+ sigusr1ed = 1;
+}
+
+/* Rehash soft expiration timers on SIGUSR2. */
+static void
+rehash_timers(void)
+{
+#if 0
+ /* XXX - not yet */
+ log_print("SIGUSR2 received, rehashing soft expiration timers.");
+
+ timer_rehash_timers();
+#endif
+}
+
+static void
+sigusr2(int sig)
+{
+ sigusr2ed = 1;
+}
+
+static int
+phase2_sa_check(struct sa *sa, void *arg)
+{
+ return sa->phase == 2;
+}
+
+static void
+daemon_shutdown(void)
+{
+ /* Perform a (protocol-wise) clean shutdown of the daemon. */
+ struct sa *sa;
+
+ if (sigtermed == 1) {
+ log_print("isakmpd: shutting down...");
+
+ /* Delete all active phase 2 SAs. */
+ while ((sa = sa_find(phase2_sa_check, NULL))) {
+ /* Each DELETE is another (outgoing) message. */
+ sa_delete(sa, 1);
+ }
+ sigtermed++;
+ }
+ if (transport_prio_sendqs_empty()) {
+ /*
+ * When the prioritized transport sendq:s are empty, i.e all
+ * the DELETE notifications have been sent, we can shutdown.
+ */
+
+#ifdef USE_DEBUG
+ log_packet_stop();
+#endif
+ /* Remove FIFO and pid files. */
+ unlink(ui_fifo);
+ unlink(pid_file);
+ log_print("isakmpd: exit");
+ exit(0);
+ }
+}
+
+/* Called on SIGTERM, SIGINT or by ui_shutdown_daemon(). */
+void
+daemon_shutdown_now(int sig)
+{
+ sigtermed = 1;
+}
+
+/* Write pid file. */
+static void
+write_pid_file(void)
+{
+ FILE *fp;
+
+ /* Ignore errors. This will fail with USE_PRIVSEP. */
+ unlink(pid_file);
+
+ fp = monitor_fopen(pid_file, "w");
+ if (fp != NULL) {
+ if (fprintf(fp, "%ld\n", (long) getpid()) < 0)
+ log_error("write_pid_file: failed to write PID to "
+ "\"%.100s\"", pid_file);
+ fclose(fp);
+ } else
+ log_fatal("write_pid_file: fopen (\"%.100s\", \"w\") failed",
+ pid_file);
+}
+
+int
+main(int argc, char *argv[])
+{
+ fd_set *rfds, *wfds;
+ int n, m;
+ size_t mask_size;
+ struct timeval tv, *timeout;
+
+#if defined (HAVE_CLOSEFROM) && (!defined (OpenBSD) || (OpenBSD >= 200405))
+ closefrom(STDERR_FILENO + 1);
+#else
+ m = getdtablesize();
+ for (n = STDERR_FILENO + 1; n < m; n++)
+ (void) close(n);
+#endif
+
+ /*
+ * Make sure init() won't alloc fd 0, 1 or 2, as daemon() will close
+ * them.
+ */
+ for (n = 0; n <= 2; n++)
+ if (fcntl(n, F_GETFL, 0) == -1 && errno == EBADF)
+ (void) open("/dev/null", n ? O_WRONLY : O_RDONLY, 0);
+
+ for (n = 1; n < _NSIG; n++)
+ signal(n, SIG_DFL);
+
+ /* Log cmd line parsing and initialization errors to stderr. */
+ log_to(stderr);
+ parse_args(argc, argv);
+ log_init(debug);
+
+ /* Open protocols and services databases. */
+ setprotoent(1);
+ setservent(1);
+
+ /*
+ * Do a clean daemon shutdown on TERM/INT. These signals must be
+ * initialized before monitor_init(). INT is only used with '-d'.
+ */
+ signal(SIGTERM, daemon_shutdown_now);
+ if (debug == 1) /* i.e '-dd' will skip this. */
+ signal(SIGINT, daemon_shutdown_now);
+
+ /* Daemonize before forking unpriv'ed child */
+ if (!debug)
+ if (daemon(0, 0))
+ log_fatal("main: daemon (0, 0) failed");
+
+ /* Set timezone before priv'separation */
+ tzset();
+
+#if defined (USE_PRIVSEP)
+ if (monitor_init(debug)) {
+ /* The parent, with privileges enters infinite monitor loop. */
+ monitor_loop(debug);
+ exit(0); /* Never reached. */
+ }
+ /* Child process only from this point on, no privileges left. */
+#endif
+
+ init();
+
+ write_pid_file();
+
+ /* Reinitialize on HUP reception. */
+ signal(SIGHUP, sighup);
+
+ /* Report state on USR1 reception. */
+ signal(SIGUSR1, sigusr1);
+
+ /* Rehash soft expiration timers on USR2 reception. */
+ signal(SIGUSR2, sigusr2);
+
+#if defined (USE_DEBUG)
+ /* If we wanted IKE packet capture to file, initialize it now. */
+ if (pcap_file != 0)
+ log_packet_init(pcap_file);
+#endif
+
+ /* Allocate the file descriptor sets just big enough. */
+ n = getdtablesize();
+ mask_size = howmany(n, NFDBITS) * sizeof(fd_mask);
+ rfds = (fd_set *) malloc(mask_size);
+ if (!rfds)
+ log_fatal("main: malloc (%lu) failed",
+ (unsigned long)mask_size);
+ wfds = (fd_set *) malloc(mask_size);
+ if (!wfds)
+ log_fatal("main: malloc (%lu) failed",
+ (unsigned long)mask_size);
+
+#if defined (USE_PRIVSEP)
+ monitor_init_done();
+#endif
+
+ while (1) {
+ /* If someone has sent SIGHUP to us, reconfigure. */
+ if (sighupped) {
+ sighupped = 0;
+ log_print("SIGHUP received");
+ reinit();
+ }
+ /* and if someone sent SIGUSR1, do a state report. */
+ if (sigusr1ed) {
+ sigusr1ed = 0;
+ log_print("SIGUSR1 received");
+ report();
+ }
+ /* and if someone sent SIGUSR2, do a timer rehash. */
+ if (sigusr2ed) {
+ sigusr2ed = 0;
+ log_print("SIGUSR2 received");
+ rehash_timers();
+ }
+ /*
+ * and if someone set 'sigtermed' (SIGTERM, SIGINT or via the
+ * UI), this indicates we should start a controlled shutdown
+ * of the daemon.
+ *
+ * Note: Since _one_ message is sent per iteration of this
+ * enclosing while-loop, and we want to send a number of
+ * DELETE notifications, we must loop atleast this number of
+ * times. The daemon_shutdown() function starts by queueing
+ * the DELETEs, all other calls just increments the
+ * 'sigtermed' variable until it reaches a "safe" value, and
+ * the daemon exits.
+ */
+ if (sigtermed)
+ daemon_shutdown();
+
+ /* Setup the descriptors to look for incoming messages at. */
+ memset(rfds, 0, mask_size);
+ n = transport_fd_set(rfds);
+ FD_SET(ui_socket, rfds);
+ if (ui_socket + 1 > n)
+ n = ui_socket + 1;
+
+ /*
+ * XXX Some day we might want to deal with an abstract
+ * application class instead, with many instantiations
+ * possible.
+ */
+ if (!app_none && app_socket >= 0) {
+ FD_SET(app_socket, rfds);
+ if (app_socket + 1 > n)
+ n = app_socket + 1;
+ }
+ /* Setup the descriptors that have pending messages to send. */
+ memset(wfds, 0, mask_size);
+ m = transport_pending_wfd_set(wfds);
+ if (m > n)
+ n = m;
+
+ /* Find out when the next timed event is. */
+ timeout = &tv;
+ timer_next_event(&timeout);
+
+ n = select(n, rfds, wfds, 0, timeout);
+ if (n == -1) {
+ if (errno != EINTR) {
+ log_error("main: select");
+
+ /*
+ * In order to give the unexpected error
+ * condition time to resolve without letting
+ * this process eat up all available CPU
+ * we sleep for a short while.
+ */
+ sleep(1);
+ }
+ } else if (n) {
+ transport_handle_messages(rfds);
+ transport_send_messages(wfds);
+ if (FD_ISSET(ui_socket, rfds))
+ ui_handler();
+ if (!app_none && app_socket >= 0 &&
+ FD_ISSET(app_socket, rfds))
+ app_handler();
+ }
+ timer_handle_expirations();
+ }
+}
diff --git a/keyexchange/isakmpd-20041012/isakmpd.conf.5 b/keyexchange/isakmpd-20041012/isakmpd.conf.5
new file mode 100644
index 0000000..db3dd78
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmpd.conf.5
@@ -0,0 +1,1126 @@
+.\" $OpenBSD: isakmpd.conf.5,v 1.94 2004/08/10 15:59:10 ho Exp $
+.\" $EOM: isakmpd.conf.5,v 1.57 2000/12/21 14:43:17 ho Exp $
+.\"
+.\" Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved.
+.\" Copyright (c) 2000, 2001, 2002 Håkan Olsson. 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+.\"
+.\" Manual page, using -mandoc macros
+.\"
+.Dd August 07, 2002
+.Dt ISAKMPD.CONF 5
+.Os
+.Sh NAME
+.Nm isakmpd.conf
+.Nd configuration file for isakmpd
+.Sh DESCRIPTION
+.Nm
+is the configuration file for the
+.Nm isakmpd
+daemon managing security association and key management for the
+IPsec layer of the kernel's networking stack.
+.Pp
+The file is of a well known type of format called .INI style, named after
+the suffix used by an overrated windowing environment for its configuration
+files.
+This format consists of sections, each beginning with a line looking like:
+.Bd -literal
+[Section name]
+.Ed
+Between the brackets is the name of the section following this section header.
+Inside a section many tag/value pairs can be stored, each one looking like:
+.Bd -literal
+Tag=Value
+.Ed
+If the value needs more space than fits on a single line it's possible to
+continue it on the next by ending the first with a backslash character
+immediately before the newline character.
+This method can extend a value for an arbitrary number of lines.
+.Pp
+Comments can be put anywhere in the file by using a hash mark
+.Pq Sq \&# .
+The comment extends to the end of the current line.
+.Pp
+Often the right-hand side values consist of other section names.
+This results in a tree structure.
+Some values are treated as a list of several scalar values.
+Such lists always use a comma character as the separator.
+Some values are formatted like this: X,Y:Z, which
+is an offer/accept syntax, where X is a value we offer and Y:Z is a range of
+accepted values, inclusive.
+.Pp
+To activate changes to
+.Nm
+without restarting
+.Nm isakmpd ,
+send a
+.Dv SIGHUP
+signal to the daemon process.
+.Ss Auto-generated parts of the configuration
+.Pp
+Some predefined section names are recognized by the daemon, avoiding the need
+to fully specify the Main Mode transforms and Quick Mode suites, protocols,
+and transforms.
+.Pp
+For Main Mode:
+.Bd -filled -compact
+.Ar {DES,BLF,3DES,CAST,AES}-{MD5,SHA}[-GRP{1,2,5,14}][-{DSS,RSA_SIG}]
+.Ed
+.Pp
+For Quick Mode:
+.Bd -filled -compact
+.Ar QM-{proto}[-TRP]-{cipher}[-{hash}][-PFS[-{group}]]-SUITE
+.Ed
+.Bd -literal
+ where
+ {proto} is either ESP or AH
+ {cipher} is either DES, 3DES, CAST, BLF or AES
+ {hash} is either MD5, SHA, RIPEMD, SHA2-{256,384,512}
+ {group} is either GRP1, GRP2, GRP5 or GRP14
+.Ed
+.Pp
+For example, 3DES-SHA means: 3DES encryption, SHA hash, and authorization by
+pre-shared keys.
+Similarly, QM-ESP-3DES-SHA-PFS-SUITE means: ESP protocol, 3DES encryption,
+SHA hash, and use Perfect Forward Secrecy.
+.Pp
+Unless explicitly stated with -GRP1, 2, 5 or 14 transforms and PFS suites
+use DH group 2.
+There are currently no predefined ESP+AH Quick Mode suites.
+.Pp
+The predefinitions include some default values for the special
+sections "General", "Keynote", "X509-certificates", and
+"Default-phase-1-configuration".
+These default values are presented in the example below.
+.Pp
+All autogenerated values can be overridden by manual entries by using the
+same section and tag names in the configuration file.
+In particular, the default phase 1 (Main or Aggressive Mode) and phase 2
+(Quick Mode) lifetimes can be overridden by these tags under the "General"
+section;
+.Bd -literal
+[General]
+Default-phase-1-lifetime= 3600,60:86400
+Default-phase-2-lifetime= 1200,60:86400
+.Ed
+.Pp
+The Main Mode lifetime currently defaults to one hour (minimum 60
+seconds, maximum 1 day).
+The Quick Mode lifetime defaults to 20 minutes
+(minimum 60 seconds, maximum 1 day).
+.Pp
+Also, the default phase 1 ID can be set by creating a <Phase1-ID>
+section, as shown below, and adding this tag under the "General"
+section;
+.Bd -literal
+[General]
+Default-phase-1-ID= Phase1-ID-name
+
+[Phase1-ID-name]
+ID-type= USER_FQDN
+Name= foo@bar.com
+.Ed
+.Ss Roots
+.Bl -hang -width 12n
+.It Em General
+Generic global configuration parameters
+.Bl -tag -width 12n
+.It Em Default-phase-1-ID
+Optional default phase 1 ID name.
+.It Em Default-phase-1-lifetime
+The default lifetime for autogenerated transforms (phase 1).
+If unspecified, the value 3600,60:86400 is used as the default.
+.It Em Default-phase-2-lifetime
+The default lifetime for autogenerated suites (phase 2).
+If unspecified, the value 1200,60:86400 is used as the default.
+.It Em Default-phase-2-suites
+A list of phase 2 suites that will be used when establishing dynamic
+SAs.
+If left unspecified, QM-ESP-3DES-SHA-PFS-SUITE is used as the default.
+.It Em Acquire-Only
+If this tag is defined,
+.Nm isakmpd
+will not set up flows automatically.
+This is useful when flows are configured with
+.Xr ipsecadm 4
+or by other programs like
+.Xr bgpd 8 .
+Thus
+.Nm isakmpd
+only takes care of the SA establishment.
+.It Em Check-interval
+The interval between watchdog checks of connections we want up at all
+times.
+.It Em DPD-check-interval
+The interval between RFC 3706 (Dead Peer Detection) messages.
+The default value is 0 (zero), which means DPD is disabled.
+.It Em Exchange-max-time
+How many seconds should an exchange maximally take to set up before we
+give up.
+.It Em Listen-on
+A list of IP-addresses OK to listen on.
+This list is used as a filter for the set of addresses the interfaces
+configured provides.
+This means that we won't see if an address given here does not exist
+on this host, and thus no error is given for that case.
+.It Em Loglevel
+A list of the form
+.Ar class Ns = Ns Ar level ,
+where both
+.Ar class
+and
+.Ar level
+are numbers.
+This is similar to the
+.Fl D
+command line switch of
+.Em isakmpd .
+See
+.Xr isakmpd 8
+for details.
+.It Em Logverbose
+If this tag is defined, whatever the value is, verbose logging is enabled.
+This is similar to the
+.Fl v
+command line switch of
+.Em isakmpd .
+See
+.Xr isakmpd 8
+for details.
+.It Em NAT-T-Keepalive
+The number of seconds between NAT-T keepalive messages, sent by the
+peer behind NAT to keep the mapping active.
+Defaults to 20.
+.It Em Policy-file
+The name of the file that contains
+.Xr keynote 4
+policies.
+The default is "/etc/isakmpd/isakmpd.policy".
+.It Em Pubkey-directory
+The directory in which
+.Nm
+looks for explicitly trusted public keys.
+The default is "/etc/isakmpd/pubkeys".
+Read
+.Xr isakmpd 8
+for the required naming convention of the files in here.
+.It Em Renegotiate-on-HUP
+If this tag is defined, whatever the value is,
+.Nm isakmpd
+will renegotiate all current phase 2 SAs when the daemon receives a
+.Dv SIGHUP
+signal, or an
+.Sq R
+is sent to the FIFO interface (see
+.Xr isakmpd 8 ) .
+.It Em Retransmits
+How many times should a message be retransmitted before giving up.
+.It Em Shared-SADB
+If this tag is defined, whatever the value is, some semantics of
+.Nm
+are changed so that multiple instances can run on top of one SADB
+and set up SAs with each other.
+Specifically this means replay
+protection will not be asked for, and errors that can occur when
+updating an SA with its parameters a 2nd time will be ignored.
+.It Em Use-Keynote
+This tag controls the use of
+.Xr keynote 4
+policy checking.
+The default value is
+.Qq yes ,
+which enables the policy checking.
+When set to any other value, policies will not be checked.
+This is useful when policies for flows and SA establishment are arranged by
+other programs like
+.Xr ipsecadm 8
+or
+.Xr bgpd 8 .
+.El
+.It Em Phase 1
+ISAKMP SA negotiation parameter root
+.Bl -tag -width 12n
+.It Em <IP-address>
+A name of the ISAKMP peer at the given IP-address.
+.It Em Default
+A name of the default ISAKMP peer.
+Incoming phase 1 connections from other IP-addresses will use this peer name.
+.It ""
+This name is used as the section name for further information to be found.
+Look at <ISAKMP-peer> below.
+.El
+.It Em Phase 2
+IPsec SA negotiation parameter root
+.Bl -tag -width 12n
+.It Em Connections
+A list of directed IPsec "connection" names that should be brought up
+automatically, either on first use if the system supports it, or at
+startup of the daemon.
+These names are section names where further information can be found.
+Look at <IPsec-connection> below.
+Normally any connections mentioned here are treated as part of the
+"Passive-connection" list we present below, however there is a
+flag: "Active-only" that disables this behaviour.
+This too is mentioned in the <IPsec-connection> section, in the "Flags" tag.
+.It Em Passive-connections
+A list of IPsec "connection" names we recognize and accept initiations for.
+These names are section names where further information can be found.
+Look at <IPsec-connection> below.
+Currently only the Local-ID and Remote-ID tags
+are looked at in those sections, as they are matched against the IDs given
+by the initiator.
+.El
+.It Em KeyNote
+.Bl -tag -width 12n
+.It Em Credential-directory
+A directory containing directories named after IDs (IP
+addresses,
+.Dq user@domain ,
+or hostnames) that contain files named
+.Dq credentials
+and
+.Dq private_key .
+.Pp
+The credentials file contains
+.Xr keynote 4
+credentials that are sent to a remote IKE daemon when we use the
+associated ID, or credentials that we may want to consider when doing
+an exchange with a remote IKE daemon that uses that ID.
+Note that, in the former case, the last credential in the file
+MUST contain our public key in its Licensees field.
+More than one credentials may exist in the file.
+They are separated by whitelines (the format is essentially the same as
+that of the policy file).
+The credentials are of the same format as the policies described in
+.Xr isakmpd.policy 5 .
+The only difference is that the Authorizer field contains a public
+key, and the assertion is signed.
+Signed assertions can be generated using the
+.Xr keynote 1
+utility.
+.Pp
+The private_key file contains the private RSA key we use for
+authentication.
+If the directory (and the files) exist, they take precedence over X509-based
+authentication.
+.El
+.It Em X509-Certificates
+.Bl -tag -width 12n
+.It Em Accept-self-signed
+If this tag is defined, whatever the value is, certificates that
+do not originate from a trusted CA but are self-signed will be
+accepted.
+.It Em Ca-directory
+A directory containing PEM certificates of certification authorities
+that we trust to sign other certificates.
+Note that for a CA to be really trusted, it needs to be somehow
+referred to by policy, in
+.Xr isakmpd.policy 5 .
+The certificates in this directory are used for the actual X.509
+authentication and for cross-referencing policies that refer to
+Distinguished Names (DNs).
+Keeping a separate directory (as opposed to integrating policies
+and X.509 CA certificates) allows for maintenance of a list of
+"well known" CAs without actually having to trust all (or any) of them.
+.It Em Cert-directory
+A directory containing PEM certificates that we trust to be valid.
+These certificates are used in preference to those passed in messages and
+are required to have a subjectAltName extension containing the certificate
+holder identity; usually IP address, FQDN, or User FQDN, as provided by
+.Xr certpatch 8 .
+.It Em Private-key
+The private key matching the public key of our certificate (which should be
+in the "Cert-directory", and have an appropriate subjectAltName field).
+.El
+.El
+.Ss Referred-to sections
+.Bl -hang -width 12n
+.It Em <ISAKMP-peer>
+Parameters for negotiation with an ISAKMP peer
+.Bl -tag -width 12n
+.It Em Phase
+The constant
+.Li 1 ,
+as ISAKMP-peers and IPsec-connections
+really are handled by the same code inside isakmpd.
+.It Em Transport
+The name of the transport protocol, defaults to
+.Li UDP .
+.It Em Port
+In case of
+.Li UDP ,
+the
+.Li UDP
+port number to send to.
+This is optional, the
+default value is 500 which is the IANA-registered number for ISAKMP.
+.It Em Local-address
+The Local IP-address to use, if we are multi-homed, or have aliases.
+.It Em Address
+If existent, the IP-address of the peer.
+.It Em Configuration
+The name of the ISAKMP-configuration section to use.
+Look at <ISAKMP-configuration> below.
+If unspecified, defaults to "Default-phase-1-configuration".
+.It Em Authentication
+If existent, authentication data for this specific peer.
+In the case of preshared key, this is the key value itself.
+.It Em ID
+If existent, the name of the section that describes the
+local client ID that we should present to our peer.
+If not present, it
+defaults to the address of the local interface we are sending packets
+over to the remote daemon.
+Look at <Phase1-ID> below.
+.It Em Remote-ID
+If existent, the name of the section that describes the remote client
+ID we expect the remote daemon to send us.
+If not present, it defaults to the address of the remote daemon.
+Look at <Phase1-ID> below.
+.It Em Flags
+A comma-separated list of flags controlling the further
+handling of the ISAKMP SA.
+Currently there are no specific ISAKMP SA flags defined.
+.El
+.It Em <Phase1-ID>
+.Bl -tag -width 12n
+.It Em ID-type
+The ID type as given by the RFC specifications.
+For phase 1 this is currently
+.Li IPV4_ADDR ,
+.Li IPV4_ADDR_SUBNET ,
+.Li IPV6_ADDR ,
+.Li IPV6_ADDR_SUBNET ,
+.Li FQDN ,
+.Li USER_FQDN
+or
+.Li KEY_ID .
+.It Em Address
+If the ID-type is
+.Li IPV4_ADDR
+or
+.Li IPV6_ADDR ,
+this tag should exist and be an IP-address.
+.It Em Network
+If the ID-type is
+.Li IPV4_ADDR_SUBNET
+or
+.Li IPV6_ADDR_SUBNET
+this tag should exist and
+be a network address.
+.It Em Netmask
+If the ID-type is
+.Li IPV4_ADDR_SUBNET
+or
+.Li IPV6_ADDR_SUBNET
+this tag should exist and
+be a network subnet mask.
+.It Em Name
+If the ID-type is
+.Li FQDN ,
+.Li USER_FQDN
+or
+.Li KEY_ID ,
+this tag should exist and contain a domain name, user@domain, or
+other identifying string respectively.
+.Pp
+In the case of
+.Li KEY_ID ,
+note that the IKE protocol allows any octet sequence to be sent or
+received under this payload, potentially including non-printable
+ones.
+.Xr isakmpd 8
+can only transmit printable
+.Li KEY_ID
+payloads, but can receive and process arbitrary
+.Li KEY_ID
+payloads.
+This effectively means that non-printable
+.Li KEY_ID
+remote identities cannot be verified through this means, although it
+is still possible to do so through
+.Xr isakmpd.policy 5 .
+.El
+.It Em <ISAKMP-configuration>
+.Bl -tag -width 12n
+.It Em DOI
+The domain of interpretation as given by the RFCs.
+Normally
+.Li IPSEC .
+If unspecified, defaults to
+.Li IPSEC .
+.It Em EXCHANGE_TYPE
+The exchange type as given by the RFCs.
+For main mode this is
+.Li ID_PROT
+and for aggressive mode it is
+.Li AGGRESSIVE .
+.It Em Transforms
+A list of proposed transforms to use for protecting the
+ISAKMP traffic.
+These are actually names for sections
+further describing the transforms.
+Look at <ISAKMP-transform> below.
+.El
+.It Em <ISAKMP-transform>
+.Bl -tag -width 12n
+.It Em ENCRYPTION_ALGORITHM
+The encryption algorithm as the RFCs name it, or ANY to denote that any
+encryption algorithm proposed will be accepted.
+.It Em KEY_LENGTH
+For encryption algorithms with variable key length, this is
+where the offered/accepted keylengths are described.
+The value is of the offer-accept kind described above.
+.It Em HASH_ALGORITHM
+The hash algorithm as the RFCs name it, or ANY.
+.It Em AUTHENTICATION_METHOD
+The authentication method as the RFCs name it, or ANY.
+.It Em GROUP_DESCRIPTION
+The group used for Diffie-Hellman exponentiations, or ANY.
+The names are symbolic, like
+.Li MODP_768 , MODP_1024 , EC_155
+and
+.Li EC_185 .
+.It Em PRF
+The algorithm to use for the keyed pseudo-random function (used for key
+derivation and authentication in phase 1), or ANY.
+.It Em Life
+A list of lifetime descriptions, or ANY.
+In the former case, each
+element is in itself a name of the section that defines the lifetime.
+Look at <Lifetime> below.
+If it is set to ANY, then any type of
+proposed lifetime type and value will be accepted.
+.El
+.It Em <Lifetime>
+.Bl -tag -width 12n
+.It Em LIFE_TYPE
+.Li SECONDS
+or
+.Li KILOBYTES
+depending on the type of the duration.
+Notice that this field may NOT be set to ANY.
+.It Em LIFE_DURATION
+An offer/accept kind of value, see above.
+Can also be set to ANY.
+.El
+.It Em <IPsec-connection>
+.Bl -tag -width 12n
+.It Em Phase
+The constant
+.Li 2 ,
+as ISAKMP-peers and IPsec-connections
+really are handled by the same code inside isakmpd.
+.It Em ISAKMP-peer
+The name of the ISAKMP-peer which to talk to in order to
+set up this connection.
+The value is the name of an <ISAKMP-peer> section.
+See above.
+.It Em Configuration
+The name of the IPsec-configuration section to use.
+Look at <IPsec-configuration> below.
+.It Em Local-ID
+If existent, the name of the section that describes the
+optional local client ID that we should present to our peer.
+It is also used when we act as responders to find out what
+<IPsec-connection> we are dealing with.
+Look at <IPsec-ID> below.
+.It Em Remote-ID
+If existent, the name of the section that describes the
+optional remote client ID that we should present to our peer.
+It is also used when we act as responders to find out what
+<IPsec-connection> we are dealing with.
+Look at <IPsec-ID> below.
+.It Em Flags
+A comma-separated list of flags controlling the further
+handling of the IPsec SA.
+Currently only one flag is defined:
+.Bl -tag -width 12n
+.It Em Active-only
+If this flag is given and this <IPsec-connection> is part of the phase 2
+connections we automatically keep up, it will not automatically be used for
+accepting connections from the peer.
+.El
+.El
+.It Em <IPsec-configuration>
+.Bl -tag -width 12n
+.It Em DOI
+The domain of interpretation as given by the RFCs.
+Normally
+.Li IPSEC .
+If unspecified, defaults to
+.Li IPSEC .
+.It Em EXCHANGE_TYPE
+The exchange type as given by the RFCs.
+For quick mode this is
+.Li QUICK_MODE .
+.It Em Suites
+A list of protection suites (bundles of protocols) usable for
+protecting the IP traffic.
+Each of the list elements is a name of an <IPsec-suite> section.
+See below.
+.El
+.It Em <IPsec-suite>
+.Bl -tag -width 12n
+.It Em Protocols
+A list of the protocols included in this protection suite.
+Each of the list elements is a name of an <IPsec-protocol>
+section.
+See below.
+.El
+.It Em <IPsec-protocol>
+.Bl -tag -width 12n
+.It Em PROTOCOL_ID
+The protocol as given by the RFCs.
+Acceptable values today are
+.Li IPSEC_AH
+and
+.Li IPSEC_ESP .
+.It Em Transforms
+A list of transforms usable for implementing the protocol.
+Each of the list elements is a name of an <IPsec-transform>
+section.
+See below.
+.It Em ReplayWindow
+The size of the window used for replay protection.
+This is normally left alone.
+Look at the
+.Nm ESP
+and
+.Nm AH
+RFCs for a better description.
+.El
+.It Em <IPsec-transform>
+.Bl -tag -width 12n
+.It Em TRANSFORM_ID
+The transform ID as given by the RFCs.
+.It Em ENCAPSULATION_MODE
+The encapsulation mode as given by the RFCs.
+This means TRANSPORT or TUNNEL.
+.It Em AUTHENTICATION_ALGORITHM
+The optional authentication algorithm in the case of this
+being an ESP transform.
+.It Em GROUP_DESCRIPTION
+An optional (provides PFS if present) Diffie-Hellman group
+description.
+The values are the same as GROUP_DESCRIPTION's
+in <ISAKMP-transform> sections shown above.
+.It Em Life
+List of lifetimes, each element is a <Lifetime> section name.
+.El
+.It Em <IPsec-ID>
+.Bl -tag -width 12n
+.It Em ID-type
+The ID type as given by the RFCs.
+For IPsec this is currently
+.Li IPV4_ADDR ,
+.Li IPV6_ADDR ,
+.Li IPV4_ADDR_SUBNET
+or
+.Li IPV6_ADDR_SUBNET .
+.It Em Address
+If the ID-type is
+.Li IPV4_ADDR
+or
+.Li IPV6_ADDR
+this tag should exist and be an IP-address.
+.It Em Network
+If the ID-type is
+.Li IPV4_ADDR_SUBNET
+or
+.Li IPV6_ADDR_SUBNET
+this tag should exist and
+be a network address.
+.It Em Netmask
+If the ID-type is
+.Li IPV4_ADDR_SUBNET
+or
+.Li IPV6_ADDR_SUBNET
+this tag should exist and
+be a network subnet mask.
+.It Em Protocol
+If the ID-type is
+.Li IPV4_ADDR ,
+.Li IPV4_ADDR_SUBNET ,
+.Li IPV6_ADDR
+or
+.Li IPV6_ADDR_SUBNET
+this tag indicates what transport protocol should be transmitted over
+the SA.
+If left unspecified, all transport protocols between the two address
+(ranges) will be sent (or permitted) over that SA.
+.It Em Port
+If the ID-type is
+.Li IPV4_ADDR ,
+.Li IPV4_ADDR_SUBNET ,
+.Li IPV6_ADDR
+or
+.Li IPV6_ADDR_SUBNET
+this tag indicates what source or destination port is allowed to be
+transported over the SA (depending on whether this is a local or
+remote ID).
+If left unspecified, all ports of the given transport protocol
+will be transmitted (or permitted) over the SA.
+The Protocol tag must be specified in conjunction with this tag.
+.El
+.El
+.Ss Other sections
+.Bl -hang -width 12n
+.It Em <IKECFG-ID>
+Parameters to use with IKE mode-config.
+One ID per peer.
+.Pp
+An IKECFG-ID is written as [<ID-type>/<name>].
+The following ID types are supported:
+.Bl -tag -width 12n
+.It IPv4
+[ipv4/A.B.C.D]
+.It IPv6
+[ipv6/abcd:abcd::ab:cd]
+.It FQDN
+[fqdn/foo.bar.org]
+.It UFQDN
+[ufqdn/user@foo.bar.org]
+.It ASN1_DN
+[asn1_dn//C=aa/O=cc/...] (Note the double slashes as the DN itself
+starts with a
+.Sq / . )
+.El
+.Pp
+Each section specifies what configuration values to return to the peer
+requesting IKE mode-config.
+Currently supported values are:
+.Bl -tag -width 12n
+.It Em Address
+The peer's network address.
+.It Em Netmask
+The peer's netmask.
+.It Em Nameserver
+The IP address of a DNS nameserver.
+.It Em WINS-server
+The IP address of a WINS server.
+.El
+.It Em <Initiator-ID>
+.Pp
+During phase 1 negotiation
+.Nm isakmpd
+looks for a pre-shared key in the <ISAKMP-peer> section.
+If no Authentication data is specified in that section, and
+.Nm isakmpd
+is not the initiator, it looks for Authentication data in a section named after
+the initiator's phase 1 ID.
+This allows mobile users with dynamic IP addresses
+to have different shared secrets.
+.Pp
+This only works for aggressive mode because in main mode the remote
+initiator ID would not yet be known.
+.Pp
+The name of the <Initiator-ID> section depends on the ID type sent by
+the initiator.
+Currently this can be:
+.Bl -tag -width 12n
+.It IPv4
+[A.B.C.D]
+.It IPv6
+[abcd:abcd::ab:cd]
+.It FQDN
+[foo.bar.org]
+.It UFQDN
+[user@foo.bar.org]
+.El
+.El
+.Sh FILES
+.Bl -tag -width /etc/isakmpd/isakmpd.conf
+.It Pa /etc/isakmpd/isakmpd.conf
+The default
+.Nm isakmpd
+configuration file.
+.It Pa /usr/share/ipsec/isakmpd/
+A directory containing some sample
+.Nm isakmpd
+configuration files.
+.El
+.Sh EXAMPLES
+An example of a configuration file:
+.Bd -literal
+# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon.
+
+[General]
+Listen-on= 10.1.0.2
+
+# Incoming phase 1 negotiations are multiplexed on the source IP address
+[Phase 1]
+10.1.0.1= ISAKMP-peer-west
+
+# These connections are walked over after config file parsing and told
+# to the application layer so that it will inform us when traffic wants to
+# pass over them.
+This means we can do on-demand keying.
+[Phase 2]
+Connections= IPsec-east-west
+
+# Default values are commented out.
+[ISAKMP-peer-west]
+Phase= 1
+#Transport= udp
+Local-address= 10.1.0.2
+Address= 10.1.0.1
+#Port= isakmp
+#Port= 500
+#Configuration= Default-phase-1-configuration
+Authentication= mekmitasdigoat
+#Flags=
+
+[IPsec-east-west]
+Phase= 2
+ISAKMP-peer= ISAKMP-peer-west
+Configuration= Default-quick-mode
+Local-ID= Net-east
+Remote-ID= Net-west
+#Flags=
+
+[Net-west]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.1.0
+Netmask= 255.255.255.0
+
+[Net-east]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.2.0
+Netmask= 255.255.255.0
+
+# Quick mode descriptions
+
+[Default-quick-mode]
+EXCHANGE_TYPE= QUICK_MODE
+Suites= QM-ESP-3DES-SHA-PFS-SUITE,QM-ESP-AES-SHA-PFS-SUITE
+
+# Data for an IKE mode-config peer
+[asn1_dn//C=SE/L=SomeCity/O=SomeCompany/CN=SomePeer.company.com]
+Address= 192.168.1.123
+Netmask= 255.255.255.0
+Nameserver= 192.168.1.10
+WINS-server= 192.168.1.11
+
+# pre-shared key based on initiator's phase 1 ID
+[foo.bar.org]
+Authentication= mekmitasdigoat
+
+#
+# #####################################################################
+# All configuration data below this point is not required as the example
+# uses the predefined Main Mode transform and Quick Mode suite names.
+# It is included here for completeness. Note the default values for the
+# [General] and [X509-certificates] sections just below.
+# #####################################################################
+#
+
+[General]
+Policy-file= /etc/isakmpd/isakmpd.policy
+Retransmits= 3
+Exchange-max-time= 120
+
+# KeyNote credential storage
+[KeyNote]
+Credential-directory= /etc/isakmpd/keynote/
+
+# Certificates stored in PEM format
+[X509-certificates]
+CA-directory= /etc/isakmpd/ca/
+Cert-directory= /etc/isakmpd/certs/
+CRL-directory= /etc/isakmpd/crls/
+Private-key= /etc/isakmpd/private/local.key
+
+# Default phase 1 description (Main Mode)
+
+[Default-phase-1-configuration]
+EXCHANGE_TYPE= ID_PROT
+Transforms= 3DES-SHA
+
+# Main mode transforms
+######################
+
+# DES
+
+[DES-MD5]
+ENCRYPTION_ALGORITHM= DES_CBC
+HASH_ALGORITHM= MD5
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_1024
+Life= Default-phase-1-lifetime
+
+[DES-SHA]
+ENCRYPTION_ALGORITHM= DES_CBC
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_1024
+Life= Default-phase-1-lifetime
+
+# 3DES
+
+[3DES-SHA]
+ENCRYPTION_ALGORITHM= 3DES_CBC
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_1024
+Life= Default-phase-1-lifetime
+
+# Blowfish
+
+[BLF-SHA]
+ENCRYPTION_ALGORITHM= BLOWFISH_CBC
+KEY_LENGTH= 128,96:192
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_1024
+Life= Default-phase-1-lifetime
+
+# Blowfish, using DH group 4 (non-default)
+[BLF-SHA-EC185]
+ENCRYPTION_ALGORITHM= BLOWFISH_CBC
+KEY_LENGTH= 128,96:192
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= EC2N_185
+Life= Default-phase-1-lifetime
+
+# Quick mode protection suites
+##############################
+
+# DES
+
+[QM-ESP-DES-SUITE]
+Protocols= QM-ESP-DES
+
+[QM-ESP-DES-PFS-SUITE]
+Protocols= QM-ESP-DES-PFS
+
+[QM-ESP-DES-MD5-SUITE]
+Protocols= QM-ESP-DES-MD5
+
+[QM-ESP-DES-MD5-PFS-SUITE]
+Protocols= QM-ESP-DES-MD5-PFS
+
+[QM-ESP-DES-SHA-SUITE]
+Protocols= QM-ESP-DES-SHA
+
+[QM-ESP-DES-SHA-PFS-SUITE]
+Protocols= QM-ESP-DES-SHA-PFS
+
+# 3DES
+
+[QM-ESP-3DES-SHA-SUITE]
+Protocols= QM-ESP-3DES-SHA
+
+[QM-ESP-3DES-SHA-PFS-SUITE]
+Protocols= QM-ESP-3DES-SHA-PFS
+
+# AES
+
+[QM-ESP-AES-SHA-SUITE]
+Protocols= QM-ESP-AES-SHA
+
+[QM-ESP-AES-SHA-PFS-SUITE]
+Protocols= QM-ESP-AES-SHA-PFS
+
+# AH
+
+[QM-AH-MD5-SUITE]
+Protocols= QM-AH-MD5
+
+[QM-AH-MD5-PFS-SUITE]
+Protocols= QM-AH-MD5-PFS
+
+# AH + ESP (non-default)
+
+[QM-AH-MD5-ESP-DES-SUITE]
+Protocols= QM-AH-MD5,QM-ESP-DES
+
+[QM-AH-MD5-ESP-DES-MD5-SUITE]
+Protocols= QM-AH-MD5,QM-ESP-DES-MD5
+
+[QM-ESP-DES-MD5-AH-MD5-SUITE]
+Protocols= QM-ESP-DES-MD5,QM-AH-MD5
+
+# Quick mode protocols
+
+# DES
+
+[QM-ESP-DES]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-DES-XF
+
+[QM-ESP-DES-MD5]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-DES-MD5-XF
+
+[QM-ESP-DES-MD5-PFS]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-DES-MD5-PFS-XF
+
+[QM-ESP-DES-SHA]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-DES-SHA-XF
+
+# 3DES
+
+[QM-ESP-3DES-SHA]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-3DES-SHA-XF
+
+[QM-ESP-3DES-SHA-PFS]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-3DES-SHA-PFS-XF
+
+[QM-ESP-3DES-SHA-TRP]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-3DES-SHA-TRP-XF
+
+# AES
+
+[QM-ESP-AES-SHA]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-AES-SHA-XF
+
+[QM-ESP-AES-SHA-PFS]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-AES-SHA-PFS-XF
+
+[QM-ESP-AES-SHA-TRP]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-AES-SHA-TRP-XF
+
+# AH MD5
+
+[QM-AH-MD5]
+PROTOCOL_ID= IPSEC_AH
+Transforms= QM-AH-MD5-XF
+
+[QM-AH-MD5-PFS]
+PROTOCOL_ID= IPSEC_AH
+Transforms= QM-AH-MD5-PFS-XF
+
+# Quick mode transforms
+
+# ESP DES+MD5
+
+[QM-ESP-DES-XF]
+TRANSFORM_ID= DES
+ENCAPSULATION_MODE= TUNNEL
+Life= Default-phase-2-lifetime
+
+[QM-ESP-DES-MD5-XF]
+TRANSFORM_ID= DES
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_MD5
+Life= Default-phase-2-lifetime
+
+[QM-ESP-DES-MD5-PFS-XF]
+TRANSFORM_ID= DES
+ENCAPSULATION_MODE= TUNNEL
+GROUP_DESCRIPTION= MODP_1024
+AUTHENTICATION_ALGORITHM= HMAC_MD5
+Life= Default-phase-2-lifetime
+
+[QM-ESP-DES-SHA-XF]
+TRANSFORM_ID= DES
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_SHA
+Life= Default-phase-2-lifetime
+
+# 3DES
+
+[QM-ESP-3DES-SHA-XF]
+TRANSFORM_ID= 3DES
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_SHA
+Life= Default-phase-2-lifetime
+
+[QM-ESP-3DES-SHA-PFS-XF]
+TRANSFORM_ID= 3DES
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_SHA
+GROUP_DESCRIPTION= MODP_1024
+Life= Default-phase-2-lifetime
+
+[QM-ESP-3DES-SHA-TRP-XF]
+TRANSFORM_ID= 3DES
+ENCAPSULATION_MODE= TRANSPORT
+AUTHENTICATION_ALGORITHM= HMAC_SHA
+Life= Default-phase-2-lifetime
+
+# AES
+
+[QM-ESP-AES-SHA-XF]
+TRANSFORM_ID= AES
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_SHA
+Life= Default-phase-2-lifetime
+
+[QM-ESP-AES-SHA-PFS-XF]
+TRANSFORM_ID= AES
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_SHA
+GROUP_DESCRIPTION= MODP_1024
+Life= Default-phase-2-lifetime
+
+[QM-ESP-AES-SHA-TRP-XF]
+TRANSFORM_ID= AES
+ENCAPSULATION_MODE= TRANSPORT
+AUTHENTICATION_ALGORITHM= HMAC_SHA
+Life= Default-phase-2-lifetime
+
+# AH
+
+[QM-AH-MD5-XF]
+TRANSFORM_ID= MD5
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_MD5
+Life= Default-phase-2-lifetime
+
+[QM-AH-MD5-PFS-XF]
+TRANSFORM_ID= MD5
+ENCAPSULATION_MODE= TUNNEL
+GROUP_DESCRIPTION= MODP_1024
+Life= Default-phase-2-lifetime
+
+[Sample-Life-Time]
+LIFE_TYPE= SECONDS
+LIFE_DURATION= 3600,1800:7200
+
+[Sample-Life-Volume]
+LIFE_TYPE= KILOBYTES
+LIFE_DURATION= 1000,768:1536
+.Ed
+.Sh SEE ALSO
+.Xr keynote 1 ,
+.Xr ipsec 4 ,
+.Xr keynote 4 ,
+.Xr isakmpd.policy 5 ,
+.Xr isakmpd 8
+.Sh BUGS
+The RFCs do not permit differing DH groups in the same proposal for
+aggressive and quick mode exchanges.
+Mixing both PFS and non-PFS suites in a quick mode proposal is not possible,
+as PFS implies using a DH group.
diff --git a/keyexchange/isakmpd-20041012/isakmpd.policy.5 b/keyexchange/isakmpd-20041012/isakmpd.policy.5
new file mode 100644
index 0000000..64800db
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmpd.policy.5
@@ -0,0 +1,638 @@
+.\" $OpenBSD: isakmpd.policy.5,v 1.35 2003/10/25 20:47:47 mcbride Exp $
+.\" $EOM: isakmpd.policy.5,v 1.24 2000/11/23 12:55:25 niklas Exp $
+.\"
+.\" Copyright (c) 1999-2001, Angelos D. Keromytis. 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+.\"
+.\"
+.\" Manual page, using -mandoc macros
+.\"
+.Dd June 15, 2002
+.Dt ISAKMPD.POLICY 5
+.Os
+.Sh NAME
+.Nm isakmpd.policy
+.Nd policy configuration file for isakmpd
+.Sh DESCRIPTION
+.Nm
+is the policy configuration file for the
+.Nm isakmpd
+daemon managing security association and key management for the
+.Xr ipsec 4
+layer of the kernel's networking stack.
+.Pp
+The
+.Xr isakmpd 8
+daemon (also known as IKE, for Internet Key Exchange) is used when two
+systems need to automatically set up a pair of Security Associations
+(SAs) for securely communicating using IPsec.
+IKE operates in two stages:
+.Pp
+In the first stage (Main or Identity Protection Mode), the two IKE
+daemons establish a secure link between themselves, fully
+authenticating each other and establishing key material for
+encrypting/authenticating future communications between them.
+This step is typically only performed once for every pair of IKE daemons.
+.Pp
+In the second stage (also called Quick Mode), the two IKE daemons
+create the pair of SAs for the parties that wish to communicate using
+IPsec.
+These parties may be the hosts the IKE daemons run on, a host
+and a network behind a firewall, or two networks behind their
+respective firewalls.
+At this stage, the exact parameters of the SAs
+(e.g., algorithms to use, encapsulation mode, lifetime) and the
+identities of the communicating parties (hosts, networks, etc.) are
+specified.
+The reason for the existence of Quick Mode is to allow for fast
+SA setup, once the more heavy-weight Main Mode has been completed.
+Generally, Quick Mode uses the key material derived from Main Mode to
+provide keys to the IPsec transforms to be used.
+Alternatively, a new
+Diffie-Hellman computation may be performed (significantly slowing
+down the exchange, but at the same time providing Perfect Forward
+Secrecy (PFS)).
+Briefly, this means that even should an attacker
+manage to break long-term keys used in other sessions (or,
+specifically, if an attacker breaks the Diffie-Hellman exchange
+performed during Main Mode), they will not be able to decrypt this
+traffic.
+Normally, no PFS is provided (the key material used by the
+IPsec SAs established as a result of this exchange will be derived
+from the key material of the Main Mode exchange), allowing for a
+faster Quick Mode exchange (no public key computations).
+.Pp
+IKE proposals are "suggestions" by the initiator of an exchange to the
+responder as to what protocols and attributes should be used on a
+class of packets.
+For example, a given exchange may ask for ESP with
+3DES and MD5 and AH with SHA1 (applied successively on the same
+packet), or just ESP with Blowfish and RIPEMD-160.
+The responder
+examines the proposals and determines which of them are acceptable,
+according to policy and any credentials.
+.Pp
+The following paragraphs assume some knowledge of the contents of the
+.Xr keynote 4
+and
+.Xr keynote 5
+man pages.
+.Pp
+In the KeyNote policy model for IPsec, no distinction is currently
+made based on the ordering of AH and ESP in the packet.
+Should this
+change in the future, an appropriate attribute (see below) will be
+added.
+.Pp
+The goal of security policy for IKE is thus to determine, based on
+local policy (provided in the
+.Nm isakmpd.policy
+file), credentials provided during the IKE exchanges (or obtained
+through other means), the SA attributes proposed during the exchange,
+and perhaps other (side-channel) information, whether a pair of SAs
+should be installed in the system (in fact, whether both the IPsec SAs
+and the flows should be installed).
+For each proposal suggested by or
+to the remote IKE daemon, the KeyNote system is consulted as to
+whether the proposal is acceptable based on local policy (contained in
+.Nm isakmpd.policy ,
+in the form of policy assertions) and remote credentials (e.g.,
+KeyNote credentials or X509 certificates provided by the remote IKE
+daemon).
+.Pp
+.Nm isakmpd.policy
+is simply a flat
+.Xr ascii 7
+file containing KeyNote policy assertions, separated by blank lines
+(note that KeyNote assertions may not contain blank lines).
+.Nm isakmpd.policy
+is read when
+.Xr isakmpd 8
+is first started, and every time it receives a
+.Dv SIGHUP
+signal.
+The new policies read will be used for all new Phase 2 (IPsec)
+SAs established from that point on (even if the associated Phase 1 SA
+was already established when the new policies were loaded).
+The policy change will not affect already established Phase 2 SAs.
+.Pp
+For more details on KeyNote assertion format, please see
+.Xr keynote 5 .
+Briefly, KeyNote policy assertions used in IKE have the following
+characteristics:
+.Bl -bullet
+.It
+The Authorizer field is typically "POLICY" (but see the examples
+below, for use of policy delegation).
+.It
+The Licensees field can be an expression of passphrases used for
+authentication of the Main Mode exchanges, and/or public keys
+(typically, X509 certificates), and/or X509 distinguished names.
+.It
+The Conditions field contains an expression of attributes from the
+IPsec policy action set (see below as well as the keynote syntax man
+page for more details).
+.It
+The ordered return-values set for IPsec policy is "false, true".
+.El
+.Pp
+For an explanation of these fields and their semantics, see
+.Xr keynote 5 .
+.Pp
+For example, the following policy assertion:
+.Bd -literal
+ Authorizer: "POLICY"
+ Licensees: "passphrase:foobar" || "x509-base64:abcd==" ||
+ "passphrase-md5-hex:3858f62230ac3c915f300c664312c63f" ||
+ "passphrase-sha1-hex:8843d7f92416211de9ebb963ff4ce28125932878"
+ Conditions: app_domain == "IPsec policy" && esp_present == "yes"
+ && esp_enc_alg != "null" -> "true";
+.Ed
+.Pp
+says that any proposal from a remote host that authenticates using the
+passphrase "foobar" or the public key contained in the X509
+certificate encoded as "abcd==" will be accepted, as long as it
+contains ESP with a non-null algorithm (i.e., the packet will be
+encrypted).
+The last two authorizers are the MD5 and SHA1 hashes respectively of
+the passphrase "foobar".
+This form may be used instead of the "passphrase:..." one to protect
+the passphrase as included in the policy file (or as distributed in a
+signed credential).
+.Pp
+The following policy assertion:
+.Bd -literal
+ Authorizer: "POLICY"
+ Licensees: "DN:/CN=CA Certificate"
+ Conditions: app_domain == "IPsec policy" && esp_present == "yes"
+ && esp_enc_alg != "null" -> "true";
+.Ed
+.Pp
+is similar to the previous one, but instead of including a complete
+X509 credential in the Licensees field, only the X509 certificate's
+Subject Canonical Name needs to be specified (note that the "DN:"
+prefix is necessary).
+.Pp
+KeyNote credentials have the same format as policy assertions, with
+one difference: the Authorizer field always contains a public key, and
+the assertion is signed (and thus its integrity can be
+cryptographically verified).
+Credentials are used to build chains of delegation of authority.
+They can be exchanged during an IKE exchange,
+or can be retrieved through some out-of-band mechanism (no such
+mechanism is currently supported in this implementation however).
+See
+.Xr isakmpd.conf 5
+on how to specify what credentials to send in an IKE exchange.
+.Pp
+Passphrases that appear in the Licensees field are encoded as the
+string "passphrase:", followed by the passphrase itself
+(case-sensitive).
+Alternatively (and preferably), they may be encoded using the
+"passphrase-md5-hex:" or "passphrase-sha1-hex:" prefixes, followed
+by the
+.Xr md5 1
+or
+.Xr sha1 1
+hash of the passphrase itself, encoded as a hexadecimal string (using
+lower-case letters only).
+.Pp
+When X509-based authentication is performed in Main Mode, any X509
+certificates received from the remote IKE daemon are converted to very
+simple KeyNote credentials.
+The conversion is straightforward: the
+issuer of the X509 certificate becomes the Authorizer of the KeyNote
+credential, the subject becomes the only Licensees entry, while the
+Conditions field simply asserts that the credential is only valid for
+"IPsec policy" use (see the app_domain action attribute below).
+.Pp
+Similarly, any X509 CA certificates present in the directory pointed
+to by the appropriate
+.Xr isakmpd.conf 5
+entry, are converted to such pseudo-credentials.
+This allows one to
+write KeyNote policies that delegate specific authority to CAs (and
+the keys those CAs certify, recursively).
+.Pp
+For more details on KeyNote assertion format, see
+.Xr keynote 5 .
+.Pp
+Information about the proposals, the identity of the remote IKE
+daemon, the packet classes to be protected, etc. are encoded in what
+is called an action set.
+The action set is composed of name-value
+attributes, similar in some ways to shell environment variables.
+These values are initialized by
+.Nm isakmpd
+before each query to the KeyNote system, and can be tested against in
+the Conditions field of assertions.
+See
+.Xr keynote 4
+and
+.Xr keynote 5
+for more details on the format and semantics of the Conditions field.
+.Pp
+Note that assertions and credentials can make references to
+non-existent attributes without catastrophic failures (access may be
+denied, depending on the overall structure, but will not be
+accidentally granted).
+One reason for credentials referencing
+non-existent attributes is that they were defined within a specific
+implementation or network only.
+.Pp
+In the following attribute set, IPv4 addresses are encoded as ASCII
+strings in the usual dotted-quad format.
+However, all quads are three digits long.
+For example, the IPv4 address
+.Va 10.128.1.12
+would be encoded as
+.Va 010.128.001.012 .
+Similarly, IPv6 addresses are encoded in the standard x:x:x:x:x:x:x:x
+format, where the 'x's are the hexadecimal values of the eight 16-bit
+pieces of the address.
+All 'x's are four digits long.
+For example, the address
+.Va 1080:0:12:0:8:800:200C:417A
+would be encoded as
+.Va 1080:0000:0012:0000:0008:0800:200C:417A .
+.Pp
+The following attributes are currently defined:
+.Bl -tag -width -indent
+.It app_domain
+Always set to
+.Va IPsec policy .
+.It doi
+Always set to
+.Va ipsec .
+.It initiator
+Set to
+.Va yes
+if the local daemon is initiating the Phase 2 SA,
+.Va no
+otherwise.
+.It phase_1
+Set to
+.Va aggressive
+if aggressive mode was used to establish the Phase 1 SA, or
+.Va main
+if main mode was used instead.
+.It pfs
+Set to
+.Va yes
+if a Diffie-Hellman exchange will be performed during this Quick Mode,
+.Va no
+otherwise.
+.It ah_present, esp_present, comp_present
+Set to
+.Va yes
+if an AH, ESP, or compression proposal was received respectively,
+.Va no
+otherwise.
+.It ah_hash_alg
+One of
+.Va md5 ,
+.Va sha ,
+.Va ripemd ,
+.Va sha2-256 ,
+.Va sha2-385 ,
+.Va sha2-512 ,
+or
+.Va des ,
+based on the hash algorithm specified in the AH proposal.
+This attribute describes the generic transform to be used in the AH
+authentication.
+.It esp_enc_alg
+One of
+.Va des ,
+.Va des-iv64 ,
+.Va 3des ,
+.Va rc4 ,
+.Va idea ,
+.Va cast ,
+.Va blowfish ,
+.Va 3idea ,
+.Va des-iv32 ,
+.Va rc4 ,
+.Va null ,
+or
+.Va aes ,
+based on the encryption algorithm specified in the ESP proposal.
+.It comp_alg
+One of
+.Va oui ,
+.Va deflate ,
+.Va lzs ,
+or
+.Va v42bis ,
+based on the compression algorithm specified in the compression
+proposal.
+.It ah_auth_alg
+One of
+.Va hmac-md5 ,
+.Va hmac-sha ,
+.Va des-mac ,
+.Va kpdk ,
+.Va hmac-sha2-256 ,
+.Va hmac-sha2-385 ,
+.Va hmac-sha2-512 ,
+or
+.Va hmac-ripemd .
+based on the authentication method specified in the AH proposal.
+.It esp_auth_alg
+One of
+.Va hmac-md5 ,
+.Va hmac-sha ,
+.Va des-mac ,
+.Va kpdk ,
+.Va hmac-sha2-256 ,
+.Va hmac-sha2-385 ,
+.Va hmac-sha2-512 ,
+or
+.Va hmac-ripemd
+based on the authentication method specified in the ESP proposal.
+.It ah_life_seconds, esp_life_seconds, comp_life_seconds
+Set to the lifetime of the AH, ESP, and compression proposal, in
+seconds.
+If no lifetime was proposed for the corresponding protocol
+(e.g., there was no proposal for AH), the corresponding attribute will
+be set to zero.
+.It ah_life_kbytes, esp_life_kbytes, comp_life_kbytes
+Set to the lifetime of the AH, ESP, and compression proposal, in
+kbytes of traffic.
+If no lifetime was proposed for the corresponding
+protocol (e.g., there was no proposal for AH), the corresponding
+attribute will be set to zero.
+.It ah_encapsulation, esp_encapsulation, comp_encapsulation
+Set to
+.Va tunnel
+or
+.Va transport ,
+based on the AH, ESP, and compression proposal.
+.It ah_ecn, esp_ecn, comp_ecn
+Set to
+.Va yes
+or
+.Va no ,
+based on whether ECN was requested for the IPsec tunnel.
+.It comp_dict_size
+Specifies the log2 maximum size of the dictionary, according to the
+compression proposal.
+.It comp_private_alg
+Set to an integer specifying the private algorithm in use, according
+to the compression proposal.
+.It ah_key_length, esp_key_length
+The number of key bits to be used by the authentication and encryption
+algorithms respectively (for variable key-size algorithms).
+.It ah_key_rounds, esp_key length
+The number of rounds of the authentication and encryption algorithms
+respectively (for variable round algorithms).
+.It ah_group_desc, esp_group_desc, comp_group_desc
+The Diffie-Hellman group identifier from the AH, ESP, and compression
+proposal, used for PFS during Quick Mode (see the pfs attribute
+above).
+If more than one of these attributes are set to a value other
+than zero, they should have the same value (in valid IKE proposals).
+Valid values are 1 (768-bit MODP), 2 (1024-bit MODP), 3 (155-bit EC),
+4 (185-bit EC), and 5 (1536-bit MODP).
+.It phase1_group_desc
+The Diffie-Hellman group identifier used in IKE Phase 1.
+Takes the same values as
+.Va ah_group_desc .
+.It remote_filter_type, local_filter_type, remote_id_type
+Set to
+.Va IPv4 address ,
+.Va IPv4 range ,
+.Va IPv4 subnet ,
+.Va IPv6 address ,
+.Va IPv6 range ,
+.Va IPv6 subnet ,
+.Va FQDN ,
+.Va User FQDN ,
+.Va ASN1 DN ,
+.Va ASN1 GN ,
+or
+.Va Key ID ,
+based on the Quick Mode Initiator ID, Quick Mode Responder ID, and
+Main Mode peer ID respectively.
+.It remote_filter_addr_upper, local_filter_addr_upper, remote_id_addr_upper
+When the corresponding filter_type is
+.Va IPv4 address
+or
+.Va IPv6 address ,
+these contain the respective address.
+For
+.Va IPv4 range
+or
+.Va IPv6 range ,
+they contain the upper end of the address range.
+For
+.Va IPv4 subnet
+or
+.Va IPv6 subnet ,
+they contain the highest address in the specified subnet.
+.It remote_filter_addr_lower, local_filter_addr_lower, remote_id_addr_lower
+When the corresponding filter_type is
+.Va IPv4 address
+or
+.Va IPv6 address ,
+these contain the respective address.
+For
+.Va IPv4 range
+or
+.Va IPv6 range ,
+these contain the lower end of the address range.
+For
+.Va IPv4 subnet
+or
+.Va IPv6 subnet ,
+these contain the lowest address in the specified subnet.
+.It remote_filter, local_filter, remote_id
+When the corresponding filter_type specifies an address range or
+subnet, these are set to the upper and lower part of the address
+space separated by a dash ('-') character (if the type specifies a
+single address, they are set to that address).
+.Pp
+For FQDN and User FQDN types, these are set to the respective string.
+For Key ID, these are set to the hexadecimal representation of the
+associated byte string (lower-case letters used) if the Key ID payload
+contains non-printable characters.
+Otherwise, they are set to the respective string.
+.Pp
+For ASN1 DN, these are set to the text encoding of the Distinguished
+Name in the payload sent or received.
+The format is the same as that used in the Licensees field.
+.It remote_filter_port, local_filter_port, remote_id_port
+Set to the transport protocol port.
+.It remote_filter_proto, local_filter_proto, remote_id_proto
+Set to
+.Va etherip ,
+.Va tcp ,
+.Va udp ,
+or the transport protocol number, depending on the transport protocol set
+in the IDci, IDcr, and Main Mode peer ID respectively.
+.It remote_negotiation_address
+Set to the IPv4 or IPv6 address of the remote IKE daemon.
+.It local_negotiation_address
+Set to the IPv4 or IPv6 address of the local interface used by the local IKE
+daemon for this exchange.
+.It GMTTimeOfDay
+Set to the UTC date/time, in YYYYMMDDHHmmSS format.
+.It LocalTimeOfDay
+Set to the local date/time, in YYYYMMDDHHmmSS format.
+.El
+.Sh FILES
+.Bl -tag -width /etc/isakmpd/isakmpd.policy
+.It Pa /etc/isakmpd/isakmpd.policy
+The default
+.Nm isakmpd
+policy configuration file.
+.It Pa /usr/share/ipsec/isakmpd/policy
+A sample
+.Nm isakmpd
+policy configuration file.
+.El
+.Sh EXAMPLES
+.Bd -literal
+ Authorizer: "POLICY"
+ Comment: This bare-bones assertion accepts everything
+
+
+
+ Authorizer: "POLICY"
+ Licensees: "passphrase-md5-hex:10838982612aff543e2e62a67c786550"
+ Comment: This policy accepts anyone using shared-secret
+ authentication using the password mekmitasisgoat,
+ and does ESP with some form of encryption (not null).
+ Conditions: app_domain == "IPsec policy" &&
+ esp_present == "yes" &&
+ esp_enc_alg != "null" -> "true";
+
+
+
+ Authorizer: "POLICY"
+ Licensees: "subpolicy1" || "subpolicy2"
+ Comment: Delegate to two other sub-policies, so we
+ can manage our policy better. Since these subpolicies
+ are not "owned" by a key (and are thus unsigned), they
+ have to be in isakmpd.policy.
+ Conditions: app_domain == "IPsec policy";
+
+
+
+ KeyNote-Version: 2
+ Licensees: "passphrase-md5-hex:9c42a1346e333a770904b2a2b37fa7d3"
+ Conditions: esp_present == "yes" -> "true";
+ Authorizer: "subpolicy1"
+
+
+
+ Conditions: ah_present == "yes" ->
+ {
+ ah_auth_alg == "md5" -> "true";
+ ah_auth_alg == "sha" &&
+ esp_present == "no" -> "true";
+ };
+ Licensees: "passphrase:otherpassword" ||
+ "passphrase-sha1-hex:f5ed6e4abd30c36a89409b5da7ecb542c9fbf00f"
+ Authorizer: "subpolicy2"
+
+
+
+ keynote-version: 2
+ comment: this is an example of a policy delegating to a CN.
+ authorizer: "POLICY"
+ licensees: "DN:/CN=CA Certificate/emailAddress=ca@foo.bar.com"
+
+
+
+ keynote-version: 2
+ comment: This is an example of a policy delegating to a key.
+ authorizer: "POLICY"
+ licensees: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\
+ FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\
+ NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\
+ m91cC5jby51azAeFw05OTEwMTEyMjQ5MzhaFw05OTExMTAyMjQ5\\
+ MzhaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\
+ GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\
+ dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\
+ QCxyAte2HEVouXg1Yu+vDihbnjDRn+6k00Rv6cZqbwA3BQ30mC/\\
+ 3TFJ09VGXCaM0UKfpnxIpkBYLmOA3FWkKI0RvPU7E1AhKkhC1Ds\\
+ PSBFjYHrB15T5lYzgfwKJCIxTDzZDx2iobUgPa0FRNGVUjpQ4/k\\
+ MJ2BF4Wh7zY3X08rMzsQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\
+ DWJ5pbTcE7iKHWLQTMYiz8i9jGi5+Eo1yr1Bab90tgaGQV0zrRH\\
+ jDHgAAy1h8WSXuyQrXfgbx2rnWFPhx9CfmuAXn7sZmQE3mnUqeP\\
+ ZL2dW87jdBGqtoUdNcoz5zKBkC943yasNui/O01MiqgadTThTJH\\
+ d1Pn17LbJC1ZVRNjR5"
+ conditions: app_domain == "IPsec policy" && doi == "ipsec" &&
+ pfs == "yes" && esp_present == "yes" && ah_present == "no" &&
+ (esp_enc_alg == "3des" || esp_enc_alg == "aes") -> "true";
+
+
+
+ keynote-version: 2
+ comment: This is an example of a credential, the signature does
+ not really verify (although the keys are real).
+ licensees: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\
+ FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\
+ NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\
+ m91cC5jby51azAeFw05OTEwMTEyMzA2MjJaFw05OTExMTAyMzA2\\
+ MjJaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\
+ GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\
+ dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\
+ QDaCs+JAB6YRKAVkoi1NkOpE1V3syApjBj0Ahjq5HqYAACo1JhM\\
+ +QsPwuSWCNhBT51HX6G6UzfY3mOUz/vou6MJ/wor8EdeTX4nucx\\
+ NSz/r6XI262aXezAp+GdBviuJZx3Q67ON/IWYrB4QtvihI4bMn5\\
+ E55nF6TKtUMJTdATvs/wIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\
+ MaQOSkaiR8id0h6Zo0VSB4HpBnjpWqz1jNG8N4RPN0W8muRA2b9\\
+ 85GNP1bkC3fK1ZPpFTB0A76lLn11CfhAf/gV1iz3ELlUHo5J8nx\\
+ Pu6XfsGJm3HsXJOuvOog8Aean4ODo4KInuAsnbLzpGl0d+Jqa5u\\
+ TZUxsyg4QOBwYEU92H"
+ authorizer: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\
+ FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\
+ NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\
+ m91cC5jby51azAeFw05OTEwMTEyMjQ5MzhaFw05OTExMTAyMjQ5\\
+ MzhaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\
+ GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\
+ dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\
+ QCxyAte2HEVouXg1Yu+vDihbnjDRn+6k00Rv6cZqbwA3BQ30mC/\\
+ 3TFJ09VGXCaM0UKfpnxIpkBYLmOA3FWkKI0RvPU7E1AhKkhC1Ds\\
+ PSBFjYHrB15T5lYzgfwKJCIxTDzZDx2iobUgPa0FRNGVUjpQ4/k\\
+ MJ2BF4Wh7zY3X08rMzsQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\
+ DWJ5pbTcE7iKHWLQTMYiz8i9jGi5+Eo1yr1Bab90tgaGQV0zrRH\\
+ jDHgAAy1h8WSXuyQrXfgbx2rnWFPhx9CfmuAXn7sZmQE3mnUqeP\\
+ ZL2dW87jdBGqtoUdNcoz5zKBkC943yasNui/O01MiqgadTThTJH\\
+ d1Pn17LbJC1ZVRNjR5"
+conditions: app_domain == "IPsec policy" && doi == "ipsec" &&
+ pfs == "yes" && esp_present == "yes" && ah_present == "no" &&
+ (esp_enc_alg == "3des" || esp_enc_alg == "aes") -> "true";
+Signature: "sig-x509-sha1-base64:ql+vrUxv14DcBOQHR2jsbXayq6T\\
+ mmtMiUB745a8rjwSrQwh+KIVDlUrghPnqhSIkWSDi9oWWMbfg\\
+ mkdudZ0wjgeTLMI2NI4GibMMsToakOKMex/0q4cpdpln3DKcQ\\
+ IcjzRv4khDws69FT3QfELjcpShvbLrXmh1Z00OFmxjyqDw="
+.Ed
+.Sh SEE ALSO
+.Xr ipsec 4 ,
+.Xr keynote 4 ,
+.Xr keynote 5 ,
+.Xr isakmpd 8
+.Sh BUGS
+A more sane way of expressing IPv6 address ranges is needed.
diff --git a/keyexchange/isakmpd-20041012/key.c b/keyexchange/isakmpd-20041012/key.c
new file mode 100644
index 0000000..bc3c9fc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/key.c
@@ -0,0 +1,213 @@
+/* $OpenBSD: key.c,v 1.19 2004/09/17 13:53:08 ho Exp $ */
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * Copyright (c) 2000-2001 Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "sysdep.h"
+
+#include "key.h"
+#include "libcrypto.h"
+#include "log.h"
+#include "util.h"
+#ifdef USE_X509
+#include "x509.h"
+#endif
+
+void
+key_free(int type, int private, void *key)
+{
+ switch (type) {
+ case ISAKMP_KEY_PASSPHRASE:
+ free(key);
+ break;
+ case ISAKMP_KEY_RSA:
+#ifdef USE_X509
+ RSA_free(key);
+ break;
+#endif
+ case ISAKMP_KEY_NONE:
+ default:
+ log_error("key_free: unknown/unsupportedkey type %d", type);
+ break;
+ }
+}
+
+/* Convert from internal form to serialized */
+void
+key_serialize(int type, int private, void *key, u_int8_t **data,
+ size_t *datalenp)
+{
+#ifdef USE_X509
+ u_int8_t *p;
+ size_t datalen;
+#endif
+
+ switch (type) {
+ case ISAKMP_KEY_PASSPHRASE:
+ *datalenp = strlen((char *)key);
+ *data = (u_int8_t *)strdup((char *)key);
+ break;
+ case ISAKMP_KEY_RSA:
+#ifdef USE_X509
+ switch (private) {
+ case ISAKMP_KEYTYPE_PUBLIC:
+ datalen = i2d_RSAPublicKey((RSA *)key, NULL);
+ *data = p = malloc(datalen);
+ if (!p) {
+ log_error("key_serialize: malloc (%lu) failed",
+ (unsigned long)datalen);
+ return;
+ }
+ *datalenp = i2d_RSAPublicKey((RSA *) key, &p);
+ break;
+
+ case ISAKMP_KEYTYPE_PRIVATE:
+ datalen = i2d_RSAPrivateKey((RSA *)key, NULL);
+ *data = p = malloc(datalen);
+ if (!p) {
+ log_error("key_serialize: malloc (%lu) failed",
+ (unsigned long)datalen);
+ return;
+ }
+ *datalenp = i2d_RSAPrivateKey((RSA *)key, &p);
+ break;
+ }
+#endif
+ break;
+ default:
+ log_error("key_serialize: unknown/unsupported key type %d",
+ type);
+ break;
+ }
+}
+
+/* Convert from serialized to printable */
+char *
+key_printable(int type, int private, u_int8_t *data, int datalen)
+{
+#ifdef USE_X509
+ char *s;
+ int i;
+#endif
+
+ switch (type) {
+ case ISAKMP_KEY_PASSPHRASE:
+ return strdup((char *)data);
+
+ case ISAKMP_KEY_RSA:
+#ifdef USE_X509
+ s = malloc(datalen * 2 + 1);
+ if (!s) {
+ log_error("key_printable: malloc (%d) failed",
+ datalen * 2 + 1);
+ return 0;
+ }
+ for (i = 0; i < datalen; i++)
+ snprintf(s + (2 * i), 2 * (datalen - i) + 1, "%02x",
+ data[i]);
+ return s;
+#endif
+
+ default:
+ log_error("key_printable: unknown/unsupported key type %d",
+ type);
+ return 0;
+ }
+}
+
+/* Convert from serialized to internal. */
+void *
+key_internalize(int type, int private, u_int8_t *data, int datalen)
+{
+ switch (type) {
+ case ISAKMP_KEY_PASSPHRASE:
+ return strdup((char *)data);
+ case ISAKMP_KEY_RSA:
+#ifdef USE_X509
+ switch (private) {
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ case ISAKMP_KEYTYPE_PUBLIC:
+ return d2i_RSAPublicKey(NULL,
+ (const u_int8_t **)&data, datalen);
+ case ISAKMP_KEYTYPE_PRIVATE:
+ return d2i_RSAPrivateKey(NULL,
+ (const u_int8_t **)&data, datalen);
+#else
+ case ISAKMP_KEYTYPE_PUBLIC:
+ return d2i_RSAPublicKey(NULL, &data, datalen);
+ case ISAKMP_KEYTYPE_PRIVATE:
+ return d2i_RSAPrivateKey(NULL, &data, datalen);
+#endif
+ default:
+ log_error("key_internalize: not public or private "
+ "RSA key passed");
+ return 0;
+ }
+ break;
+#endif /* USE_X509 */
+ default:
+ log_error("key_internalize: unknown/unsupported key type %d",
+ type);
+ break;
+ }
+
+ return 0;
+}
+
+/* Convert from printable to serialized */
+void
+key_from_printable(int type, int private, char *key, u_int8_t **data,
+ u_int32_t *datalenp)
+{
+#ifdef USE_X509
+ u_int32_t datalen;
+#endif
+
+ switch (type) {
+ case ISAKMP_KEY_PASSPHRASE:
+ *datalenp = strlen(key);
+ *data = (u_int8_t *) strdup(key);
+ break;
+
+ case ISAKMP_KEY_RSA:
+#ifdef USE_X509
+ datalen = (strlen(key) + 1) / 2; /* Round up, just in case */
+ *data = malloc(datalen);
+ if (!*data) {
+ log_error("key_from_printable: malloc (%d) failed",
+ datalen);
+ *datalenp = 0;
+ return;
+ }
+ *datalenp = hex2raw(key, *data, datalen);
+ break;
+#endif
+
+ default:
+ log_error("key_from_printable: "
+ "unknown/unsupported key type %d", type);
+ *data = NULL;
+ *datalenp = 0;
+ break;
+ }
+}
diff --git a/keyexchange/isakmpd-20041012/key.h b/keyexchange/isakmpd-20041012/key.h
new file mode 100644
index 0000000..81b1328
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/key.h
@@ -0,0 +1,39 @@
+/* $OpenBSD: key.h,v 1.7 2004/04/15 18:39:26 deraadt Exp $ */
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * Copyright (c) 2000-2001 Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#ifndef _KEY_H_
+#define _KEY_H_
+
+#define ISAKMP_KEY_NONE 0
+#define ISAKMP_KEY_PASSPHRASE 1
+#define ISAKMP_KEY_RSA 2
+#define ISAKMP_KEY_DSA 3
+
+#define ISAKMP_KEYTYPE_PUBLIC 0
+#define ISAKMP_KEYTYPE_PRIVATE 1
+
+void key_free(int, int, void *);
+void key_serialize(int, int, void *, u_int8_t **, size_t *);
+char *key_printable(int, int, u_int8_t *, int);
+void key_from_printable(int, int, char *, u_int8_t **, u_int32_t *);
+void *key_internalize(int, int, u_int8_t *, int);
+#endif /* _KEY_H_ */
diff --git a/keyexchange/isakmpd-20041012/libcrypto.c b/keyexchange/isakmpd-20041012/libcrypto.c
new file mode 100644
index 0000000..d66c58a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/libcrypto.c
@@ -0,0 +1,49 @@
+/* $OpenBSD: libcrypto.c,v 1.16 2004/04/15 18:39:26 deraadt Exp $ */
+/* $EOM: libcrypto.c,v 1.14 2000/09/28 12:53:27 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000 Angelos D. Keromytis. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include "sysdep.h"
+#include "libcrypto.h"
+
+void
+libcrypto_init(void)
+{
+#if defined (USE_X509) && defined (USE_LIBCRYPTO)
+
+ /* Add all algorithms known by SSL */
+#if OPENSSL_VERSION_NUMBER >= 0x00905100L
+ OpenSSL_add_all_algorithms();
+#else
+ SSLeay_add_all_algorithms();
+#endif
+
+#endif /* USE_X509 && USE_LIBCRYPTO */
+}
diff --git a/keyexchange/isakmpd-20041012/libcrypto.h b/keyexchange/isakmpd-20041012/libcrypto.h
new file mode 100644
index 0000000..e9581bf
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/libcrypto.h
@@ -0,0 +1,52 @@
+/* $OpenBSD: libcrypto.h,v 1.16 2004/04/15 18:39:26 deraadt Exp $ */
+/* $EOM: libcrypto.h,v 1.16 2000/09/28 12:53:27 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000 Angelos D. Keromytis. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _LIBCRYPTO_H_
+#define _LIBCRYPTO_H_
+
+#ifdef USE_X509
+
+#include <stdio.h>
+
+/* XXX I want #include <ssl/cryptall.h> but we appear to not install meth.h */
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/md5.h>
+#include <openssl/pem.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/x509.h>
+
+#endif /* USE_X509 */
+
+extern void libcrypto_init(void);
+
+#endif /* _LIBCRYPTO_H_ */
diff --git a/keyexchange/isakmpd-20041012/log.c b/keyexchange/isakmpd-20041012/log.c
new file mode 100644
index 0000000..5d8080c
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/log.c
@@ -0,0 +1,706 @@
+/* $OpenBSD: log.c,v 1.49 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001, 2003 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef USE_DEBUG
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_PCAP
+#include <pcap.h>
+#else
+#include "sysdep/common/pcap.h"
+#endif
+
+#endif /* USE_DEBUG */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "conf.h"
+#include "isakmp_num.h"
+#include "log.h"
+#include "monitor.h"
+#include "util.h"
+
+static void _log_print(int, int, const char *, va_list, int, int);
+
+static FILE *log_output;
+
+int verbose_logging = 0;
+#if defined (USE_DEBUG)
+static int log_level[LOG_ENDCLASS];
+
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+#define SNAPLEN (64 * 1024)
+
+struct packhdr {
+ struct pcap_pkthdr pcap;/* pcap file packet header */
+ union {
+ struct ip ip4; /* IPv4 header (w/o options) */
+ struct ip6_hdr ip6; /* IPv6 header */
+ } ip;
+};
+
+struct isakmp_hdr {
+ u_int8_t icookie[8], rcookie[8];
+ u_int8_t next, ver, type, flags;
+ u_int32_t msgid, len;
+};
+
+static char *pcaplog_file = NULL;
+static FILE *packet_log;
+static u_int8_t *packet_buf = NULL;
+
+static int udp_cksum(struct packhdr *, const struct udphdr *,
+ u_int16_t *, int);
+static u_int16_t in_cksum(const u_int16_t *, int);
+#endif /* USE_DEBUG */
+
+void
+log_init(int debug)
+{
+ if (debug)
+ log_output = stderr;
+ else
+ log_to(0); /* syslog */
+}
+
+void
+log_reinit(void)
+{
+ struct conf_list *logging;
+#ifdef USE_DEBUG
+ struct conf_list_node *logclass;
+ int class, level;
+#endif /* USE_DEBUG */
+
+ logging = conf_get_list("General", "Logverbose");
+ if (logging) {
+ verbose_logging = 1;
+ conf_free_list(logging);
+ }
+#ifdef USE_DEBUG
+ logging = conf_get_list("General", "Loglevel");
+ if (!logging)
+ return;
+
+ for (logclass = TAILQ_FIRST(&logging->fields); logclass;
+ logclass = TAILQ_NEXT(logclass, link)) {
+ if (sscanf(logclass->field, "%d=%d", &class, &level) != 2) {
+ if (sscanf(logclass->field, "A=%d", &level) == 1)
+ for (class = 0; class < LOG_ENDCLASS; class++)
+ log_debug_cmd(class, level);
+ else {
+ log_print("init: invalid logging class or "
+ "level: %s", logclass->field);
+ continue;
+ }
+ } else
+ log_debug_cmd(class, level);
+ }
+ conf_free_list(logging);
+#endif /* USE_DEBUG */
+}
+
+void
+log_to(FILE *f)
+{
+ if (!log_output && f)
+ closelog();
+ log_output = f;
+ if (!f)
+ openlog("isakmpd", LOG_PID | LOG_CONS, LOG_DAEMON);
+}
+
+FILE *
+log_current(void)
+{
+ return log_output;
+}
+
+static char *
+_log_get_class(int error_class)
+{
+ /* XXX For test purposes. To be removed later on? */
+ static char *class_text[] = LOG_CLASSES_TEXT;
+
+ if (error_class < 0)
+ return "Dflt";
+ else if (error_class >= LOG_ENDCLASS)
+ return "Unkn";
+ else
+ return class_text[error_class];
+}
+
+static void
+_log_print(int error, int syslog_level, const char *fmt, va_list ap,
+ int class, int level)
+{
+ char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32];
+ static const char fallback_msg[] =
+ "write to log file failed (errno %d), redirecting to syslog";
+ int len;
+ struct tm *tm;
+ struct timeval now;
+ time_t t;
+
+ len = vsnprintf(buffer, sizeof buffer, fmt, ap);
+ if (len > 0 && len < (int) sizeof buffer - 1 && error)
+ snprintf(buffer + len, sizeof buffer - len, ": %s",
+ strerror(errno));
+ if (log_output) {
+ gettimeofday(&now, 0);
+ t = now.tv_sec;
+ tm = localtime(&t);
+ if (class >= 0)
+ snprintf(nbuf, sizeof nbuf,
+ "%02d%02d%02d.%06ld %s %02d ",
+ tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec,
+ _log_get_class(class), level);
+ else /* LOG_PRINT (-1) or LOG_REPORT (-2) */
+ snprintf(nbuf, sizeof nbuf, "%02d%02d%02d.%06ld %s ",
+ tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec,
+ class == LOG_PRINT ? "Default" : "Report>");
+ strlcat(nbuf, buffer, sizeof nbuf);
+#if defined (USE_PRIVSEP)
+ strlcat(nbuf, getuid() ? "" : " [priv]", LOG_SIZE + 32);
+#endif
+ strlcat(nbuf, "\n", sizeof nbuf);
+
+ if (fwrite(nbuf, strlen(nbuf), 1, log_output) == 0) {
+ /* Report fallback. */
+ syslog(LOG_ALERT, fallback_msg, errno);
+ fprintf(log_output, fallback_msg, errno);
+
+ /*
+ * Close log_output to prevent isakmpd from locking
+ * the file. We may need to explicitly close stdout
+ * to do this properly.
+ * XXX - Figure out how to match two FILE *'s and
+ * rewrite.
+ */
+ if (fileno(log_output) != -1 &&
+ fileno(stdout) == fileno(log_output))
+ fclose(stdout);
+ fclose(log_output);
+
+ /* Fallback to syslog. */
+ log_to(0);
+
+ /* (Re)send current message to syslog(). */
+ syslog(class == LOG_REPORT ? LOG_ALERT :
+ syslog_level, "%s", buffer);
+ }
+ } else
+ syslog(class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s",
+ buffer);
+}
+
+#ifdef USE_DEBUG
+void
+log_debug(int cls, int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ /*
+ * If we are not debugging this class, or the level is too low, just
+ * return.
+ */
+ if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
+ return;
+ va_start(ap, fmt);
+ _log_print(0, LOG_INFO, fmt, ap, cls, level);
+ va_end(ap);
+}
+
+void
+log_debug_buf(int cls, int level, const char *header, const u_int8_t *buf,
+ size_t sz)
+{
+ size_t i, j;
+ char s[73];
+
+ /*
+ * If we are not debugging this class, or the level is too low, just
+ * return.
+ */
+ if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
+ return;
+
+ log_debug(cls, level, "%s:", header);
+ for (i = j = 0; i < sz;) {
+ snprintf(s + j, sizeof s - j, "%02x", buf[i++]);
+ j += 2;
+ if (i % 4 == 0) {
+ if (i % 32 == 0) {
+ s[j] = '\0';
+ log_debug(cls, level, "%s", s);
+ j = 0;
+ } else
+ s[j++] = ' ';
+ }
+ }
+ if (j) {
+ s[j] = '\0';
+ log_debug(cls, level, "%s", s);
+ }
+}
+
+void
+log_debug_cmd(int cls, int level)
+{
+ if (cls < 0 || cls >= LOG_ENDCLASS) {
+ log_print("log_debug_cmd: invalid debugging class %d", cls);
+ return;
+ }
+ if (level < 0) {
+ log_print("log_debug_cmd: invalid debugging level %d for "
+ "class %d", level, cls);
+ return;
+ }
+ if (level == log_level[cls])
+ log_print("log_debug_cmd: log level unchanged for class %d",
+ cls);
+ else {
+ log_print("log_debug_cmd: log level changed from %d to %d "
+ "for class %d", log_level[cls], level, cls);
+ log_level[cls] = level;
+ }
+}
+
+void
+log_debug_toggle(void)
+{
+ static int log_level_copy[LOG_ENDCLASS], toggle = 0;
+
+ if (!toggle) {
+ LOG_DBG((LOG_MISC, 50, "log_debug_toggle: "
+ "debug levels cleared"));
+ memcpy(&log_level_copy, &log_level, sizeof log_level);
+ memset(&log_level, 0, sizeof log_level);
+ } else {
+ memcpy(&log_level, &log_level_copy, sizeof log_level);
+ LOG_DBG((LOG_MISC, 50, "log_debug_toggle: "
+ "debug levels restored"));
+ }
+ toggle = !toggle;
+}
+#endif /* USE_DEBUG */
+
+void
+log_print(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
+ va_end(ap);
+}
+
+void
+log_verbose(const char *fmt, ...)
+{
+ va_list ap;
+#ifdef USE_DEBUG
+ int i;
+#endif /* USE_DEBUG */
+
+ if (verbose_logging == 0)
+ return;
+
+#ifdef USE_DEBUG
+ for (i = 0; i < LOG_ENDCLASS; i++)
+ if (log_level[i] > 0)
+ return;
+#endif
+
+ va_start(ap, fmt);
+ _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
+ va_end(ap);
+}
+
+void
+log_error(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _log_print(1, LOG_ERR, fmt, ap, LOG_PRINT, 0);
+ va_end(ap);
+}
+
+void
+log_fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _log_print(1, LOG_CRIT, fmt, ap, LOG_PRINT, 0);
+ va_end(ap);
+#ifdef USE_PRIVSEP
+ monitor_exit(1);
+#else
+ exit(1);
+#endif
+}
+
+#ifdef USE_DEBUG
+void
+log_packet_init(char *newname)
+{
+ struct pcap_file_header sf_hdr;
+ struct stat st;
+ mode_t old_umask;
+ char *mode;
+
+ /* Allocate packet buffer first time through. */
+ if (!packet_buf)
+ packet_buf = malloc(SNAPLEN);
+
+ if (!packet_buf) {
+ log_error("log_packet_init: malloc (%d) failed", SNAPLEN);
+ return;
+ }
+ if (pcaplog_file && strcmp(pcaplog_file, PCAP_FILE_DEFAULT) != 0)
+ free(pcaplog_file);
+
+ pcaplog_file = strdup(newname);
+ if (!pcaplog_file) {
+ log_error("log_packet_init: strdup (\"%s\") failed", newname);
+ return;
+ }
+ /* Does the file already exist? XXX lstat() or stat()? */
+#if defined (USE_PRIVSEP)
+ /* XXX This is a fstat! */
+ if (monitor_stat(pcaplog_file, &st) == 0) {
+#else
+ if (lstat(pcaplog_file, &st) == 0) {
+#endif
+ /* Sanity checks. */
+ if ((st.st_mode & S_IFMT) != S_IFREG) {
+ log_print("log_packet_init: existing capture file is "
+ "not a regular file");
+ return;
+ }
+ if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+ log_print("log_packet_init: existing capture "
+ "file has bad modes");
+ return;
+ }
+ /*
+ * XXX It would be nice to check if it actually is a pcap
+ * file...
+ */
+
+ mode = "a";
+ } else
+ mode = "w";
+
+ old_umask = umask(S_IRWXG | S_IRWXO);
+ packet_log = monitor_fopen(pcaplog_file, mode);
+ umask(old_umask);
+
+ if (!packet_log) {
+ log_error("log_packet_init: fopen (\"%s\", \"%s\") failed",
+ pcaplog_file, mode);
+ return;
+ }
+ log_print("log_packet_init: "
+ "starting IKE packet capture to file \"%s\"", pcaplog_file);
+
+ /* If this is a new file, we need to write a PCAP header to it. */
+ if (*mode == 'w') {
+ sf_hdr.magic = TCPDUMP_MAGIC;
+ sf_hdr.version_major = PCAP_VERSION_MAJOR;
+ sf_hdr.version_minor = PCAP_VERSION_MINOR;
+ sf_hdr.thiszone = 0;
+ sf_hdr.snaplen = SNAPLEN;
+ sf_hdr.sigfigs = 0;
+ sf_hdr.linktype = DLT_LOOP;
+
+ fwrite((char *) &sf_hdr, sizeof sf_hdr, 1, packet_log);
+ fflush(packet_log);
+ }
+}
+
+void
+log_packet_restart(char *newname)
+{
+ if (packet_log) {
+ log_print("log_packet_restart: capture already active on "
+ "file \"%s\"", pcaplog_file);
+ return;
+ }
+ if (newname)
+ log_packet_init(newname);
+ else if (!pcaplog_file)
+ log_packet_init(PCAP_FILE_DEFAULT);
+ else
+ log_packet_init(pcaplog_file);
+}
+
+void
+log_packet_stop(void)
+{
+ /* Stop capture. */
+ if (packet_log) {
+ fclose(packet_log);
+ log_print("log_packet_stop: stopped capture");
+ }
+ packet_log = 0;
+}
+
+void
+log_packet_iov(struct sockaddr *src, struct sockaddr *dst, struct iovec *iov,
+ int iovcnt)
+{
+ struct isakmp_hdr *isakmphdr;
+ struct packhdr hdr;
+ struct udphdr udp;
+ struct timeval tv;
+ int off, datalen, hdrlen, i, add_espmarker = 0;
+ const u_int32_t espmarker = 0;
+
+ for (i = 0, datalen = 0; i < iovcnt; i++)
+ datalen += iov[i].iov_len;
+
+ if (!packet_log || datalen > SNAPLEN)
+ return;
+
+ /* copy packet into buffer */
+ for (i = 0, off = 0; i < iovcnt; i++) {
+ memcpy(packet_buf + off, iov[i].iov_base, iov[i].iov_len);
+ off += iov[i].iov_len;
+ }
+
+ memset(&hdr, 0, sizeof hdr);
+ memset(&udp, 0, sizeof udp);
+
+ /* isakmp - turn off the encryption bit in the isakmp hdr */
+ isakmphdr = (struct isakmp_hdr *) packet_buf;
+ isakmphdr->flags &= ~(ISAKMP_FLAGS_ENC);
+
+ /* udp */
+ udp.uh_sport = sockaddr_port(src);
+ udp.uh_dport = sockaddr_port(dst);
+ datalen += sizeof udp;
+#if defined (USE_NAT_TRAVERSAL)
+ if (ntohs(udp.uh_sport) == 4500 ||
+ ntohs(udp.uh_dport) == 4500) { /* XXX Quick and dirty */
+ add_espmarker = 1;
+ datalen += sizeof espmarker;
+ }
+#endif
+ udp.uh_ulen = htons(datalen);
+
+ /* ip */
+ switch (src->sa_family) {
+ default:
+ /* Assume IPv4. XXX Can 'default' ever happen here? */
+ hdr.ip.ip4.ip_src.s_addr = 0x02020202;
+ hdr.ip.ip4.ip_dst.s_addr = 0x01010101;
+ /* The rest of the setup is common to AF_INET. */
+ goto setup_ip4;
+
+ case AF_INET:
+ hdr.ip.ip4.ip_src.s_addr =
+ ((struct sockaddr_in *)src)->sin_addr.s_addr;
+ hdr.ip.ip4.ip_dst.s_addr =
+ ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+
+setup_ip4:
+ hdrlen = sizeof hdr.ip.ip4;
+ hdr.ip.ip4.ip_v = 0x4;
+ hdr.ip.ip4.ip_hl = 0x5;
+ hdr.ip.ip4.ip_p = IPPROTO_UDP;
+ hdr.ip.ip4.ip_len = htons(datalen + hdrlen);
+ /* Let's use the IP ID as a "packet counter". */
+ i = ntohs(hdr.ip.ip4.ip_id) + 1;
+ hdr.ip.ip4.ip_id = htons(i);
+ /* Calculate IP header checksum. */
+ hdr.ip.ip4.ip_sum = in_cksum((u_int16_t *) & hdr.ip.ip4,
+ hdr.ip.ip4.ip_hl << 2);
+ break;
+
+ case AF_INET6:
+ hdrlen = sizeof(hdr.ip.ip6);
+ hdr.ip.ip6.ip6_vfc = IPV6_VERSION;
+ hdr.ip.ip6.ip6_nxt = IPPROTO_UDP;
+ hdr.ip.ip6.ip6_plen = udp.uh_ulen;
+ memcpy(&hdr.ip.ip6.ip6_src,
+ &((struct sockaddr_in6 *)src)->sin6_addr,
+ sizeof hdr.ip.ip6.ip6_src);
+ memcpy(&hdr.ip.ip6.ip6_dst,
+ &((struct sockaddr_in6 *)dst)->sin6_addr,
+ sizeof hdr.ip.ip6.ip6_dst);
+ break;
+ }
+
+ /* Calculate UDP checksum. */
+ udp.uh_sum = udp_cksum(&hdr, &udp, (u_int16_t *) packet_buf, src->sa_family);
+ /* pcap file packet header */
+ gettimeofday(&tv, 0);
+ hdr.pcap.ts.tv_sec = tv.tv_sec;
+ hdr.pcap.ts.tv_usec = tv.tv_usec;
+ hdr.pcap.caplen = datalen + hdrlen;
+ hdr.pcap.len = datalen + hdrlen;
+
+ hdrlen += sizeof(struct pcap_pkthdr);
+ datalen -= sizeof(struct udphdr);
+
+ /* Write to pcap file. */
+ fwrite(&hdr, hdrlen, 1, packet_log); /* pcap + IP */
+ fwrite(&udp, sizeof(struct udphdr), 1, packet_log); /* UDP */
+ if (add_espmarker) {
+ fwrite(&espmarker, sizeof espmarker, 1, packet_log);
+ datalen -= sizeof espmarker;
+ }
+ fwrite(packet_buf, datalen, 1, packet_log); /* IKE-data */
+ fflush(packet_log);
+}
+
+/* Copied from tcpdump/print-udp.c, mostly rewritten. */
+static int
+udp_cksum(struct packhdr *hdr, const struct udphdr *u, u_int16_t *d, int af)
+{
+ struct ip *ip4;
+ struct ip6_hdr *ip6;
+ int i, hdrlen, tlen = ntohs(u->uh_ulen) - sizeof(struct udphdr);
+
+ union phu {
+ struct ip4pseudo {
+ struct in_addr src;
+ struct in_addr dst;
+ u_int8_t z;
+ u_int8_t proto;
+ u_int16_t len;
+ } ip4p;
+ struct ip6pseudo {
+ struct in6_addr src;
+ struct in6_addr dst;
+ u_int32_t plen;
+ u_int16_t z0;
+ u_int8_t z1;
+ u_int8_t nxt;
+ } ip6p;
+ u_int16_t pa[20];
+ } phu;
+ const u_int16_t *sp;
+ u_int32_t sum;
+
+ /* Setup pseudoheader. */
+ memset(phu.pa, 0, sizeof phu);
+ switch (af) {
+ case AF_INET:
+ ip4 = &hdr->ip.ip4;
+ memcpy(&phu.ip4p.src, &ip4->ip_src, sizeof(struct in_addr));
+ memcpy(&phu.ip4p.dst, &ip4->ip_dst, sizeof(struct in_addr));
+ phu.ip4p.proto = ip4->ip_p;
+ phu.ip4p.len = u->uh_ulen;
+ hdrlen = sizeof phu.ip4p;
+ break;
+
+ case AF_INET6:
+ ip6 = &hdr->ip.ip6;
+ memcpy(&phu.ip6p.src, &ip6->ip6_src, sizeof(phu.ip6p.src));
+ memcpy(&phu.ip6p.dst, &ip6->ip6_dst, sizeof(phu.ip6p.dst));
+ phu.ip6p.plen = u->uh_ulen;
+ phu.ip6p.nxt = ip6->ip6_nxt;
+ hdrlen = sizeof phu.ip6p;
+ break;
+
+ default:
+ return 0;
+ }
+
+ /* IPv6 wants a 0xFFFF checksum "on error", not 0x0. */
+ if (tlen < 0)
+ return (af == AF_INET ? 0 : 0xFFFF);
+
+ sum = 0;
+ for (i = 0; i < hdrlen; i += 2)
+ sum += phu.pa[i / 2];
+
+ sp = (u_int16_t *) u;
+ for (i = 0; i < (int)sizeof(struct udphdr); i += 2)
+ sum += *sp++;
+
+ sp = d;
+ for (i = 0; i < (tlen & ~1); i += 2)
+ sum += *sp++;
+
+ if (tlen & 1)
+ sum += htons((*(const char *)sp) << 8);
+
+ while (sum > 0xffff)
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum = ~sum & 0xffff;
+
+ return sum;
+}
+
+/* Copied from tcpdump/print-ip.c, modified. */
+static u_int16_t
+in_cksum(const u_int16_t *w, int len)
+{
+ int nleft = len, sum = 0;
+ u_int16_t answer;
+
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+ if (nleft == 1)
+ sum += htons(*(u_char *) w << 8);
+
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return answer;
+}
+
+#endif /* USE_DEBUG */
diff --git a/keyexchange/isakmpd-20041012/log.h b/keyexchange/isakmpd-20041012/log.h
new file mode 100644
index 0000000..dc36f5d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/log.h
@@ -0,0 +1,102 @@
+/* $OpenBSD: log.h,v 1.21 2004/05/23 18:17:56 hshoexer Exp $ */
+/* $EOM: log.h,v 1.19 2000/03/30 14:27:23 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001, 2002, 2003 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <stdio.h>
+
+extern int verbose_logging;
+
+/*
+ * We cannot do the log strings dynamically sizeable as out of memory is one
+ * of the situations we need to report about.
+ */
+#define LOG_SIZE 200
+
+enum log_classes {
+ LOG_MISC, LOG_TRANSPORT, LOG_MESSAGE, LOG_CRYPTO, LOG_TIMER, LOG_SYSDEP,
+ LOG_SA, LOG_EXCHANGE, LOG_NEGOTIATION, LOG_POLICY, LOG_UI, LOG_ENDCLASS
+};
+#define LOG_CLASSES_TEXT \
+ { "Misc", "Trpt", "Mesg", "Cryp", "Timr", "Sdep", "SA ", "Exch", "Negt", \
+ "Plcy", "UI " }
+
+/*
+ * "Class" LOG_REPORT will always be logged to the current log channel,
+ * regardless of level.
+ */
+#define LOG_PRINT -1
+#define LOG_REPORT -2
+
+#ifdef USE_DEBUG
+
+#define LOG_DBG(x) log_debug x
+#define LOG_DBG_BUF(x) log_debug_buf x
+
+extern void log_debug(int, int, const char *,...)
+ __attribute__((__format__(__printf__, 3, 4)));
+extern void log_debug_buf(int, int, const char *, const u_int8_t *, size_t);
+extern void log_debug_cmd(int, int);
+extern void log_debug_toggle(void);
+
+#define PCAP_FILE_DEFAULT "/var/run/isakmpd.pcap"
+extern void log_packet_init(char *);
+extern void log_packet_iov(struct sockaddr *, struct sockaddr *,
+ struct iovec *, int);
+extern void log_packet_restart(char *);
+extern void log_packet_stop(void);
+
+#else /* !USE_DEBUG */
+
+#define LOG_DBG(x)
+#define LOG_DBG_BUF(x)
+
+#endif /* USE_DEBUG */
+
+extern FILE *log_current(void);
+extern void log_error(const char *,...)
+ __attribute__((__format__(__printf__, 1, 2)));
+extern void log_fatal(const char *,...)
+ __attribute__((__format__(__printf__, 1, 2)));
+extern void log_print(const char *,...)
+ __attribute__((__format__(__printf__, 1, 2)));
+extern void log_verbose(const char *,...)
+ __attribute__((__format__(__printf__, 1, 2)));
+extern void log_to(FILE *);
+extern void log_init(int);
+extern void log_reinit(void);
+
+#endif /* _LOG_H_ */
diff --git a/keyexchange/isakmpd-20041012/math_2n.c b/keyexchange/isakmpd-20041012/math_2n.c
new file mode 100644
index 0000000..f8828ef
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/math_2n.c
@@ -0,0 +1,1107 @@
+/* $OpenBSD: math_2n.c,v 1.16 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: math_2n.c,v 1.15 1999/04/20 09:23:30 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * B2N is a module for doing arithmetic on the Field GF(2**n) which is
+ * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an
+ * irreduciable polynomial over GF(2)[x] with grade n.
+ *
+ * First we need functions which operate on GF(2)[x], operation
+ * on GF(2)[x]/p(x) can be done as for Z_p then.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "sysdep.h"
+
+#include "math_2n.h"
+#include "util.h"
+
+static u_int8_t hex2int(char);
+
+static char int2hex[] = "0123456789abcdef";
+CHUNK_TYPE b2n_mask[CHUNK_BITS] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+#if CHUNK_BITS > 8
+ 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
+#if CHUNK_BITS > 16
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+#endif
+#endif
+};
+
+/* Convert a hex character to its integer value. */
+static u_int8_t
+hex2int(char c)
+{
+ if (c <= '9')
+ return c - '0';
+ if (c <= 'f')
+ return 10 + c - 'a';
+
+ return 0;
+}
+
+int
+b2n_random(b2n_ptr n, u_int32_t bits)
+{
+ if (b2n_resize(n, (CHUNK_MASK + bits) >> CHUNK_SHIFTS))
+ return -1;
+
+ getrandom((u_int8_t *) n->limp, CHUNK_BYTES * n->chunks);
+
+ /* Get the number of significant bits right */
+ if (bits & CHUNK_MASK) {
+ CHUNK_TYPE m =
+ (((1 << ((bits & CHUNK_MASK) - 1)) - 1) << 1) | 1;
+ n->limp[n->chunks - 1] &= m;
+ }
+ n->dirty = 1;
+ return 0;
+}
+
+/* b2n management functions */
+
+void
+b2n_init(b2n_ptr n)
+{
+ n->chunks = 0;
+ n->limp = 0;
+}
+
+void
+b2n_clear(b2n_ptr n)
+{
+ if (n->limp)
+ free(n->limp);
+}
+
+int
+b2n_resize(b2n_ptr n, unsigned int chunks)
+{
+ size_t old = n->chunks;
+ size_t size;
+ CHUNK_TYPE *new;
+
+ if (chunks == 0)
+ chunks = 1;
+
+ if (chunks == old)
+ return 0;
+
+ size = CHUNK_BYTES * chunks;
+
+ new = realloc(n->limp, size);
+ if (!new)
+ return -1;
+
+ n->limp = new;
+ n->chunks = chunks;
+ n->bits = chunks << CHUNK_SHIFTS;
+ n->dirty = 1;
+
+ if (chunks > old)
+ memset(n->limp + old, 0, size - CHUNK_BYTES * old);
+
+ return 0;
+}
+
+/* Simple assignment functions. */
+
+int
+b2n_set(b2n_ptr d, b2n_ptr s)
+{
+ if (d == s)
+ return 0;
+
+ b2n_sigbit(s);
+ if (b2n_resize(d, (CHUNK_MASK + s->bits) >> CHUNK_SHIFTS))
+ return -1;
+ memcpy(d->limp, s->limp, CHUNK_BYTES * d->chunks);
+ d->bits = s->bits;
+ d->dirty = s->dirty;
+ return 0;
+}
+
+int
+b2n_set_null(b2n_ptr n)
+{
+ if (b2n_resize(n, 1))
+ return -1;
+ n->limp[0] = n->bits = n->dirty = 0;
+ return 0;
+}
+
+int
+b2n_set_ui(b2n_ptr n, unsigned int val)
+{
+#if CHUNK_BITS < 32
+ int i, chunks;
+
+ chunks = (CHUNK_BYTES - 1 + sizeof(val)) / CHUNK_BYTES;
+
+ if (b2n_resize(n, chunks))
+ return -1;
+
+ for (i = 0; i < chunks; i++) {
+ n->limp[i] = val & CHUNK_BMASK;
+ val >>= CHUNK_BITS;
+ }
+#else
+ if (b2n_resize(n, 1))
+ return -1;
+ n->limp[0] = val;
+#endif
+ n->dirty = 1;
+ return 0;
+}
+
+/* XXX This one only takes hex at the moment. */
+int
+b2n_set_str(b2n_ptr n, char *str)
+{
+ int i, j, w, len, chunks;
+ CHUNK_TYPE tmp;
+
+ if (strncasecmp(str, "0x", 2))
+ return -1;
+
+ /* Make the hex string even lengthed */
+ len = strlen(str) - 2;
+ if (len & 1) {
+ len++;
+ str++;
+ } else
+ str += 2;
+
+ len /= 2;
+
+ chunks = (CHUNK_BYTES - 1 + len) / CHUNK_BYTES;
+ if (b2n_resize(n, chunks))
+ return -1;
+ memset(n->limp, 0, CHUNK_BYTES * n->chunks);
+
+ for (w = 0, i = 0; i < chunks; i++) {
+ tmp = 0;
+ for (j = (i == 0 ?
+ ((len - 1) % CHUNK_BYTES) + 1 : CHUNK_BYTES);
+ j > 0; j--) {
+ tmp <<= 8;
+ tmp |= (hex2int(str[w]) << 4) | hex2int(str[w + 1]);
+ w += 2;
+ }
+ n->limp[chunks - 1 - i] = tmp;
+ }
+
+ n->dirty = 1;
+ return 0;
+}
+
+/* Output function, mainly for debugging purposes. */
+void
+b2n_print(b2n_ptr n)
+{
+ int i, j, w, flag = 0;
+ int left;
+ char buffer[2 * CHUNK_BYTES];
+ CHUNK_TYPE tmp;
+
+ left = ((((7 + b2n_sigbit(n)) >> 3) - 1) % CHUNK_BYTES) + 1;
+ printf("0x");
+ for (i = 0; i < n->chunks; i++) {
+ tmp = n->limp[n->chunks - 1 - i];
+ memset(buffer, '0', sizeof(buffer));
+ for (w = 0, j = (i == 0 ? left : CHUNK_BYTES); j > 0; j--) {
+ buffer[w++] = int2hex[(tmp >> 4) & 0xf];
+ buffer[w++] = int2hex[tmp & 0xf];
+ tmp >>= 8;
+ }
+
+ for (j = (i == 0 ? left - 1 : CHUNK_BYTES - 1); j >= 0; j--)
+ if (flag || (i == n->chunks - 1 && j == 0) ||
+ buffer[2 * j] != '0' || buffer[2 * j + 1] != '0') {
+ putchar(buffer[2 * j]);
+ putchar(buffer[2 * j + 1]);
+ flag = 1;
+ }
+ }
+ printf("\n");
+}
+
+int
+b2n_snprint(char *buf, size_t sz, b2n_ptr n)
+{
+ int i, j, w, flag = 0;
+ size_t k;
+ int left;
+ char buffer[2 * CHUNK_BYTES];
+ CHUNK_TYPE tmp;
+
+ left = ((((7 + b2n_sigbit(n)) >> 3) - 1) % CHUNK_BYTES) + 1;
+
+ k = strlcpy(buf, "0x", sz);
+ for (i = 0; i < n->chunks && k < sz - 1; i++) {
+ tmp = n->limp[n->chunks - 1 - i];
+ memset(buffer, '0', sizeof(buffer));
+ for (w = 0, j = (i == 0 ? left : CHUNK_BYTES); j > 0; j--) {
+ buffer[w++] = int2hex[(tmp >> 4) & 0xf];
+ buffer[w++] = int2hex[tmp & 0xf];
+ tmp >>= 8;
+ }
+
+ for (j = (i == 0 ? left - 1 : CHUNK_BYTES - 1); j >= 0
+ && k < sz - 3; j--)
+ if (flag || (i == n->chunks - 1 && j == 0) ||
+ buffer[2 * j] != '0' || buffer[2 * j + 1] != '0') {
+ buf[k++] = buffer[2 * j];
+ buf[k++] = buffer[2 * j + 1];
+ flag = 1;
+ }
+ }
+
+ buf[k++] = 0;
+ return k;
+}
+
+/* Arithmetic functions. */
+
+u_int32_t
+b2n_sigbit(b2n_ptr n)
+{
+ int i, j;
+
+ if (!n->dirty)
+ return n->bits;
+
+ for (i = n->chunks - 1; i > 0; i--)
+ if (n->limp[i])
+ break;
+
+ if (!n->limp[i])
+ return 0;
+
+ for (j = CHUNK_MASK; j > 0; j--)
+ if (n->limp[i] & b2n_mask[j])
+ break;
+
+ n->bits = (i << CHUNK_SHIFTS) + j + 1;
+ n->dirty = 0;
+ return n->bits;
+}
+
+/* Addition on GF(2)[x] is nice, its just an XOR. */
+int
+b2n_add(b2n_ptr d, b2n_ptr a, b2n_ptr b)
+{
+ int i;
+ b2n_ptr bmin, bmax;
+
+ if (!b2n_cmp_null(a))
+ return b2n_set(d, b);
+
+ if (!b2n_cmp_null(b))
+ return b2n_set(d, a);
+
+ bmin = B2N_MIN(a, b);
+ bmax = B2N_MAX(a, b);
+
+ if (b2n_resize(d, bmax->chunks))
+ return -1;
+
+ for (i = 0; i < bmin->chunks; i++)
+ d->limp[i] = bmax->limp[i] ^ bmin->limp[i];
+
+ /*
+ * If d is not bmax, we have to copy the rest of the bytes, and also
+ * need to adjust to number of relevant bits.
+ */
+ if (d != bmax) {
+ for (; i < bmax->chunks; i++)
+ d->limp[i] = bmax->limp[i];
+
+ d->bits = bmax->bits;
+ }
+ /*
+ * Help to converse memory. When the result of the addition is zero
+ * truncate the used amount of memory.
+ */
+ if (d != bmax && !b2n_cmp_null(d))
+ return b2n_set_null(d);
+ else
+ d->dirty = 1;
+ return 0;
+}
+
+/* Compare two polynomials. */
+int
+b2n_cmp(b2n_ptr n, b2n_ptr m)
+{
+ int sn, sm;
+ int i;
+
+ sn = b2n_sigbit(n);
+ sm = b2n_sigbit(m);
+
+ if (sn > sm)
+ return 1;
+ if (sn < sm)
+ return -1;
+
+ for (i = n->chunks - 1; i >= 0; i--)
+ if (n->limp[i] > m->limp[i])
+ return 1;
+ else if (n->limp[i] < m->limp[i])
+ return -1;
+
+ return 0;
+}
+
+int
+b2n_cmp_null(b2n_ptr a)
+{
+ int i = 0;
+
+ do {
+ if (a->limp[i])
+ return 1;
+ }
+ while (++i < a->chunks);
+
+ return 0;
+}
+
+/* Left shift, needed for polynomial multiplication. */
+int
+b2n_lshift(b2n_ptr d, b2n_ptr n, unsigned int s)
+{
+ int i, maj, min, chunks;
+ u_int16_t bits = b2n_sigbit(n), add;
+ CHUNK_TYPE *p, *op;
+
+ if (!s)
+ return b2n_set(d, n);
+
+ maj = s >> CHUNK_SHIFTS;
+ min = s & CHUNK_MASK;
+
+ add = (!(bits & CHUNK_MASK) ||
+ ((bits & CHUNK_MASK) + min) > CHUNK_MASK) ? 1 : 0;
+ chunks = n->chunks;
+ if (b2n_resize(d, chunks + maj + add))
+ return -1;
+ memmove(d->limp + maj, n->limp, CHUNK_BYTES * chunks);
+
+ if (maj)
+ memset(d->limp, 0, CHUNK_BYTES * maj);
+ if (add)
+ d->limp[d->chunks - 1] = 0;
+
+ /* If !min there are no bit shifts, we are done */
+ if (!min)
+ return 0;
+
+ op = p = &d->limp[d->chunks - 1];
+ for (i = d->chunks - 2; i >= maj; i--) {
+ op--;
+ *p = (*p << min) | (*op >> (CHUNK_BITS - min));
+ p--;
+ }
+ *p <<= min;
+
+ d->dirty = 0;
+ d->bits = bits + (maj << CHUNK_SHIFTS) + min;
+ return 0;
+}
+
+/* Right shift, needed for polynomial division. */
+int
+b2n_rshift(b2n_ptr d, b2n_ptr n, unsigned int s)
+{
+ int maj, min, size = n->chunks, newsize;
+ b2n_ptr tmp;
+
+ if (!s)
+ return b2n_set(d, n);
+
+ maj = s >> CHUNK_SHIFTS;
+
+ newsize = size - maj;
+
+ if (size < maj)
+ return b2n_set_null(d);
+
+ min = (CHUNK_BITS - (s & CHUNK_MASK)) & CHUNK_MASK;
+ if (min) {
+ if ((b2n_sigbit(n) & CHUNK_MASK) > (u_int32_t) min)
+ newsize++;
+
+ if (b2n_lshift(d, n, min))
+ return -1;
+ tmp = d;
+ } else
+ tmp = n;
+
+ memmove(d->limp, tmp->limp + maj + (min ? 1 : 0),
+ CHUNK_BYTES * newsize);
+ if (b2n_resize(d, newsize))
+ return -1;
+
+ d->bits = tmp->bits - ((maj + (min ? 1 : 0)) << CHUNK_SHIFTS);
+ return 0;
+}
+
+/* Normal polynomial multiplication. */
+int
+b2n_mul(b2n_ptr d, b2n_ptr n, b2n_ptr m)
+{
+ int i, j;
+ b2n_t tmp, tmp2;
+
+ if (!b2n_cmp_null(m) || !b2n_cmp_null(n))
+ return b2n_set_null(d);
+
+ if (b2n_sigbit(m) == 1)
+ return b2n_set(d, n);
+
+ if (b2n_sigbit(n) == 1)
+ return b2n_set(d, m);
+
+ b2n_init(tmp);
+ b2n_init(tmp2);
+
+ if (b2n_set(tmp, B2N_MAX(n, m)))
+ goto fail;
+ if (b2n_set(tmp2, B2N_MIN(n, m)))
+ goto fail;
+
+ if (b2n_set_null(d))
+ goto fail;
+
+ for (i = 0; i < tmp2->chunks; i++)
+ if (tmp2->limp[i])
+ for (j = 0; j < CHUNK_BITS; j++) {
+ if (tmp2->limp[i] & b2n_mask[j])
+ if (b2n_add(d, d, tmp))
+ goto fail;
+
+ if (b2n_lshift(tmp, tmp, 1))
+ goto fail;
+ }
+ else if (b2n_lshift(tmp, tmp, CHUNK_BITS))
+ goto fail;
+
+ b2n_clear(tmp);
+ b2n_clear(tmp2);
+ return 0;
+
+fail:
+ b2n_clear(tmp);
+ b2n_clear(tmp2);
+ return -1;
+}
+
+/*
+ * Squaring in this polynomial ring is more efficient than normal
+ * multiplication.
+ */
+int
+b2n_square(b2n_ptr d, b2n_ptr n)
+{
+ int i, j, maj, min, bits, chunk;
+ b2n_t t;
+
+ maj = b2n_sigbit(n);
+ min = maj & CHUNK_MASK;
+ maj = (maj + CHUNK_MASK) >> CHUNK_SHIFTS;
+
+ b2n_init(t);
+ if (b2n_resize(t,
+ 2 * maj + ((CHUNK_MASK + 2 * min) >> CHUNK_SHIFTS))) {
+ b2n_clear(t);
+ return -1;
+ }
+ chunk = 0;
+ bits = 0;
+
+ for (i = 0; i < maj; i++)
+ if (n->limp[i])
+ for (j = 0; j < CHUNK_BITS; j++) {
+ if (n->limp[i] & b2n_mask[j])
+ t->limp[chunk] ^= b2n_mask[bits];
+
+ bits += 2;
+ if (bits >= CHUNK_BITS) {
+ chunk++;
+ bits &= CHUNK_MASK;
+ }
+ }
+ else
+ chunk += 2;
+
+ t->dirty = 1;
+ B2N_SWAP(d, t);
+ b2n_clear(t);
+ return 0;
+}
+
+/*
+ * Normal polynomial division.
+ * These functions are far from optimal in speed.
+ */
+int
+b2n_div_q(b2n_ptr d, b2n_ptr n, b2n_ptr m)
+{
+ b2n_t r;
+ int rv;
+
+ b2n_init(r);
+ rv = b2n_div(d, r, n, m);
+ b2n_clear(r);
+ return rv;
+}
+
+int
+b2n_div_r(b2n_ptr r, b2n_ptr n, b2n_ptr m)
+{
+ b2n_t q;
+ int rv;
+
+ b2n_init(q);
+ rv = b2n_div(q, r, n, m);
+ b2n_clear(q);
+ return rv;
+}
+
+int
+b2n_div(b2n_ptr q, b2n_ptr r, b2n_ptr n, b2n_ptr m)
+{
+ int i, j, len, bits;
+ u_int32_t sm, sn;
+ b2n_t nenn, div, shift, mask;
+
+ /* If Teiler > Zaehler, the result is 0 */
+ if ((sm = b2n_sigbit(m)) > (sn = b2n_sigbit(n))) {
+ if (b2n_set_null(q))
+ return -1;
+ return b2n_set(r, n);
+ }
+ if (sm == 0)
+ /* Division by Zero */
+ return -1;
+ else if (sm == 1) {
+ /* Division by the One-Element */
+ if (b2n_set(q, n))
+ return -1;
+ return b2n_set_null(r);
+ }
+ b2n_init(nenn);
+ b2n_init(div);
+ b2n_init(shift);
+ b2n_init(mask);
+
+ if (b2n_set(nenn, n))
+ goto fail;
+ if (b2n_set(div, m))
+ goto fail;
+ if (b2n_set(shift, m))
+ goto fail;
+ if (b2n_set_ui(mask, 1))
+ goto fail;
+
+ if (b2n_resize(q, (sn - sm + CHUNK_MASK) >> CHUNK_SHIFTS))
+ goto fail;
+ memset(q->limp, 0, CHUNK_BYTES * q->chunks);
+
+ if (b2n_lshift(shift, shift, sn - sm))
+ goto fail;
+ if (b2n_lshift(mask, mask, sn - sm))
+ goto fail;
+
+ /* Number of significant octets */
+ len = (sn - 1) >> CHUNK_SHIFTS;
+ /* The first iteration is done over the relevant bits */
+ bits = (CHUNK_MASK + sn) & CHUNK_MASK;
+ for (i = len; i >= 0 && b2n_sigbit(nenn) >= sm; i--)
+ for (j = (i == len ? bits : CHUNK_MASK); j >= 0
+ && b2n_sigbit(nenn) >= sm; j--) {
+ if (nenn->limp[i] & b2n_mask[j]) {
+ if (b2n_sub(nenn, nenn, shift))
+ goto fail;
+ if (b2n_add(q, q, mask))
+ goto fail;
+ }
+ if (b2n_rshift(shift, shift, 1))
+ goto fail;
+ if (b2n_rshift(mask, mask, 1))
+ goto fail;
+ }
+
+ B2N_SWAP(r, nenn);
+
+ b2n_clear(nenn);
+ b2n_clear(div);
+ b2n_clear(shift);
+ b2n_clear(mask);
+ return 0;
+
+fail:
+ b2n_clear(nenn);
+ b2n_clear(div);
+ b2n_clear(shift);
+ b2n_clear(mask);
+ return -1;
+}
+
+/* Functions for Operation on GF(2**n) ~= GF(2)[x]/p(x). */
+int
+b2n_mod(b2n_ptr m, b2n_ptr n, b2n_ptr p)
+{
+ int bits, size;
+
+ if (b2n_div_r(m, n, p))
+ return -1;
+
+ bits = b2n_sigbit(m);
+ size = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS);
+ if (size == 0)
+ size = 1;
+ if (m->chunks > size)
+ if (b2n_resize(m, size))
+ return -1;
+
+ m->bits = bits;
+ m->dirty = 0;
+ return 0;
+}
+
+int
+b2n_gcd(b2n_ptr e, b2n_ptr go, b2n_ptr ho)
+{
+ b2n_t g, h;
+
+ b2n_init(g);
+ b2n_init(h);
+ if (b2n_set(g, go))
+ goto fail;
+ if (b2n_set(h, ho))
+ goto fail;
+
+ while (b2n_cmp_null(h)) {
+ if (b2n_mod(g, g, h))
+ goto fail;
+ B2N_SWAP(g, h);
+ }
+
+ B2N_SWAP(e, g);
+
+ b2n_clear(g);
+ b2n_clear(h);
+ return 0;
+
+fail:
+ b2n_clear(g);
+ b2n_clear(h);
+ return -1;
+}
+
+int
+b2n_mul_inv(b2n_ptr ga, b2n_ptr be, b2n_ptr p)
+{
+ b2n_t a;
+
+ b2n_init(a);
+ if (b2n_set_ui(a, 1))
+ goto fail;
+
+ if (b2n_div_mod(ga, a, be, p))
+ goto fail;
+
+ b2n_clear(a);
+ return 0;
+
+fail:
+ b2n_clear(a);
+ return -1;
+}
+
+int
+b2n_div_mod(b2n_ptr ga, b2n_ptr a, b2n_ptr be, b2n_ptr p)
+{
+ b2n_t s0, s1, s2, q, r0, r1;
+
+ /* There is no multiplicative inverse to Null. */
+ if (!b2n_cmp_null(be))
+ return b2n_set_null(ga);
+
+ b2n_init(s0);
+ b2n_init(s1);
+ b2n_init(s2);
+ b2n_init(r0);
+ b2n_init(r1);
+ b2n_init(q);
+
+ if (b2n_set(r0, p))
+ goto fail;
+ if (b2n_set(r1, be))
+ goto fail;
+
+ if (b2n_set_null(s0))
+ goto fail;
+ if (b2n_set(s1, a))
+ goto fail;
+
+ while (b2n_cmp_null(r1)) {
+ if (b2n_div(q, r0, r0, r1))
+ goto fail;
+ B2N_SWAP(r0, r1);
+
+ if (b2n_mul(s2, q, s1))
+ goto fail;
+ if (b2n_mod(s2, s2, p))
+ goto fail;
+ if (b2n_sub(s2, s0, s2))
+ goto fail;
+
+ B2N_SWAP(s0, s1);
+ B2N_SWAP(s1, s2);
+ }
+ B2N_SWAP(ga, s0);
+
+ b2n_clear(s0);
+ b2n_clear(s1);
+ b2n_clear(s2);
+ b2n_clear(r0);
+ b2n_clear(r1);
+ b2n_clear(q);
+ return 0;
+
+fail:
+ b2n_clear(s0);
+ b2n_clear(s1);
+ b2n_clear(s2);
+ b2n_clear(r0);
+ b2n_clear(r1);
+ b2n_clear(q);
+ return -1;
+}
+
+/*
+ * The trace tells us if there do exist any square roots
+ * for 'a' in GF(2)[x]/p(x). The number of square roots is
+ * 2 - 2*Trace.
+ * If z is a square root, z + 1 is the other.
+ */
+int
+b2n_trace(b2n_ptr ho, b2n_ptr a, b2n_ptr p)
+{
+ int i, m = b2n_sigbit(p) - 1;
+ b2n_t h;
+
+ b2n_init(h);
+ if (b2n_set(h, a))
+ goto fail;
+
+ for (i = 0; i < m - 1; i++) {
+ if (b2n_square(h, h))
+ goto fail;
+ if (b2n_mod(h, h, p))
+ goto fail;
+
+ if (b2n_add(h, h, a))
+ goto fail;
+ }
+ B2N_SWAP(ho, h);
+
+ b2n_clear(h);
+ return 0;
+
+fail:
+ b2n_clear(h);
+ return -1;
+}
+
+/*
+ * The halftrace yields the square root if the degree of the
+ * irreduceable polynomial is odd.
+ */
+int
+b2n_halftrace(b2n_ptr ho, b2n_ptr a, b2n_ptr p)
+{
+ int i, m = b2n_sigbit(p) - 1;
+ b2n_t h;
+
+ b2n_init(h);
+ if (b2n_set(h, a))
+ goto fail;
+
+ for (i = 0; i < (m - 1) / 2; i++) {
+ if (b2n_square(h, h))
+ goto fail;
+ if (b2n_mod(h, h, p))
+ goto fail;
+ if (b2n_square(h, h))
+ goto fail;
+ if (b2n_mod(h, h, p))
+ goto fail;
+
+ if (b2n_add(h, h, a))
+ goto fail;
+ }
+
+ B2N_SWAP(ho, h);
+
+ b2n_clear(h);
+ return 0;
+
+fail:
+ b2n_clear(h);
+ return -1;
+}
+
+/*
+ * Solving the equation: y**2 + y = b in GF(2**m) where ip is the
+ * irreduceable polynomial. If m is odd, use the half trace.
+ */
+int
+b2n_sqrt(b2n_ptr zo, b2n_ptr b, b2n_ptr ip)
+{
+ int i, m = b2n_sigbit(ip) - 1;
+ b2n_t w, p, temp, z;
+
+ if (!b2n_cmp_null(b))
+ return b2n_set_null(z);
+
+ if (m & 1)
+ return b2n_halftrace(zo, b, ip);
+
+ b2n_init(z);
+ b2n_init(w);
+ b2n_init(p);
+ b2n_init(temp);
+
+ do {
+ if (b2n_random(p, m))
+ goto fail;
+ if (b2n_set_null(z))
+ goto fail;
+ if (b2n_set(w, p))
+ goto fail;
+
+ for (i = 1; i < m; i++) {
+ if (b2n_square(z, z)) /* z**2 */
+ goto fail;
+ if (b2n_mod(z, z, ip))
+ goto fail;
+
+ if (b2n_square(w, w)) /* w**2 */
+ goto fail;
+ if (b2n_mod(w, w, ip))
+ goto fail;
+
+ if (b2n_mul(temp, w, b)) /* w**2 * b */
+ goto fail;
+ if (b2n_mod(temp, temp, ip))
+ goto fail;
+ if (b2n_add(z, z, temp)) /* z**2 + w**2 + b */
+ goto fail;
+
+ if (b2n_add(w, w, p)) /* w**2 + p */
+ goto fail;
+ }
+ }
+ while (!b2n_cmp_null(w));
+
+ B2N_SWAP(zo, z);
+
+ b2n_clear(w);
+ b2n_clear(p);
+ b2n_clear(temp);
+ b2n_clear(z);
+ return 0;
+
+fail:
+ b2n_clear(w);
+ b2n_clear(p);
+ b2n_clear(temp);
+ b2n_clear(z);
+ return -1;
+}
+
+/* Exponentiation modulo a polynomial. */
+int
+b2n_exp_mod(b2n_ptr d, b2n_ptr b0, u_int32_t e, b2n_ptr p)
+{
+ b2n_t u, b;
+
+ b2n_init(u);
+ b2n_init(b);
+ if (b2n_set_ui(u, 1))
+ goto fail;
+ if (b2n_mod(b, b0, p))
+ goto fail;
+
+ while (e) {
+ if (e & 1) {
+ if (b2n_mul(u, u, b))
+ goto fail;
+ if (b2n_mod(u, u, p))
+ goto fail;
+ }
+ if (b2n_square(b, b))
+ goto fail;
+ if (b2n_mod(b, b, p))
+ goto fail;
+ e >>= 1;
+ }
+
+ B2N_SWAP(d, u);
+
+ b2n_clear(u);
+ b2n_clear(b);
+ return 0;
+
+fail:
+ b2n_clear(u);
+ b2n_clear(b);
+ return -1;
+}
+
+/*
+ * Low-level function to speed up scalar multiplication with
+ * elliptic curves.
+ * Multiplies a normal number by 3.
+ */
+
+/* Normal addition behaves as Z_{2**n} and not F_{2**n}. */
+int
+b2n_nadd(b2n_ptr d0, b2n_ptr a0, b2n_ptr b0)
+{
+ int i, carry;
+ b2n_ptr a, b;
+ b2n_t d;
+
+ if (!b2n_cmp_null(a0))
+ return b2n_set(d0, b0);
+
+ if (!b2n_cmp_null(b0))
+ return b2n_set(d0, a0);
+
+ b2n_init(d);
+ a = B2N_MAX(a0, b0);
+ b = B2N_MIN(a0, b0);
+
+ if (b2n_resize(d, a->chunks + 1)) {
+ b2n_clear(d);
+ return -1;
+ }
+ for (carry = i = 0; i < b->chunks; i++) {
+ d->limp[i] = a->limp[i] + b->limp[i] + carry;
+ carry = (d->limp[i] < a->limp[i] ? 1 : 0);
+ }
+
+ for (; i < a->chunks && carry; i++) {
+ d->limp[i] = a->limp[i] + carry;
+ carry = (d->limp[i] < a->limp[i] ? 1 : 0);
+ }
+
+ if (i < a->chunks)
+ memcpy(d->limp + i, a->limp + i,
+ CHUNK_BYTES * (a->chunks - i));
+
+ d->dirty = 1;
+ B2N_SWAP(d0, d);
+
+ b2n_clear(d);
+ return 0;
+}
+
+/* Very special sub, a > b. */
+int
+b2n_nsub(b2n_ptr d0, b2n_ptr a, b2n_ptr b)
+{
+ int i, carry;
+ b2n_t d;
+
+ if (b2n_cmp(a, b) <= 0)
+ return b2n_set_null(d0);
+
+ b2n_init(d);
+ if (b2n_resize(d, a->chunks)) {
+ b2n_clear(d);
+ return -1;
+ }
+ for (carry = i = 0; i < b->chunks; i++) {
+ d->limp[i] = a->limp[i] - b->limp[i] - carry;
+ carry = (d->limp[i] > a->limp[i] ? 1 : 0);
+ }
+
+ for (; i < a->chunks && carry; i++) {
+ d->limp[i] = a->limp[i] - carry;
+ carry = (d->limp[i] > a->limp[i] ? 1 : 0);
+ }
+
+ if (i < a->chunks)
+ memcpy(d->limp + i, a->limp + i,
+ CHUNK_BYTES * (a->chunks - i));
+
+ d->dirty = 1;
+
+ B2N_SWAP(d0, d);
+
+ b2n_clear(d);
+ return 0;
+}
+
+int
+b2n_3mul(b2n_ptr d0, b2n_ptr e)
+{
+ b2n_t d;
+
+ b2n_init(d);
+ if (b2n_lshift(d, e, 1))
+ goto fail;
+
+ if (b2n_nadd(d0, d, e))
+ goto fail;
+
+ b2n_clear(d);
+ return 0;
+
+fail:
+ b2n_clear(d);
+ return -1;
+}
diff --git a/keyexchange/isakmpd-20041012/math_2n.h b/keyexchange/isakmpd-20041012/math_2n.h
new file mode 100644
index 0000000..0515199
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/math_2n.h
@@ -0,0 +1,132 @@
+/* $OpenBSD: math_2n.h,v 1.7 2004/04/15 18:39:26 deraadt Exp $ */
+/* $EOM: math_2n.h,v 1.9 1999/04/17 23:20:32 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MATH_2N_H
+#define _MATH_2N_H_
+
+/*
+ * The chunk size we use is variable, this allows speed ups
+ * for processors like the Alpha with 64bit words.
+ * XXX - b2n_mask is only up to 32 bit at the moment.
+ */
+
+#define USE_32BIT /* XXX - This obviously needs fixing */
+
+#ifdef USE_32BIT
+#define CHUNK_TYPE u_int32_t
+#define CHUNK_BITS 32
+#define CHUNK_SHIFTS 5
+#define CHUNK_BMASK 0xffffffff
+#define CHUNK_MASK (CHUNK_BITS - 1)
+#define CHUNK_BYTES (CHUNK_BITS >> 3)
+#define CHUNK_NIBBLES (CHUNK_BITS >> 2)
+#else
+#define CHUNK_TYPE u_int8_t
+#define CHUNK_BITS 8
+#define CHUNK_SHIFTS 3
+#define CHUNK_BMASK 0xff
+#define CHUNK_MASK (CHUNK_BITS - 1)
+#define CHUNK_BYTES (CHUNK_BITS >> 3)
+#define CHUNK_NIBBLES (CHUNK_BITS >> 2)
+#endif
+
+extern CHUNK_TYPE b2n_mask[CHUNK_BITS];
+
+/* An element of GF(2**n), n = bits */
+
+typedef struct {
+ u_int16_t chunks;
+ u_int16_t bits;
+ u_int8_t dirty; /* Sig bits are dirty */
+ CHUNK_TYPE *limp;
+} _b2n;
+
+typedef _b2n *b2n_ptr;
+typedef _b2n b2n_t[1];
+
+#define B2N_SET(x,y) do \
+ { \
+ (x)->chunks = (y)->chunks; \
+ (x)->bits = (y)->bits; \
+ (x)->limp = (y)->limp; \
+ (x)->dirty = (y)->dirty; \
+ } \
+while (0)
+
+#define B2N_SWAP(x,y) do \
+ { \
+ b2n_t _t_; \
+\
+ B2N_SET (_t_, (x)); \
+ B2N_SET ((x), (y)); \
+ B2N_SET ((y), _t_); \
+ } \
+while (0)
+
+#define B2N_MIN(x,y) ((x)->chunks > (y)->chunks ? (y) : (x))
+#define B2N_MAX(x,y) ((x)->chunks > (y)->chunks ? (x) : (y))
+
+int b2n_3mul(b2n_ptr, b2n_ptr);
+int b2n_add(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_cmp(b2n_ptr, b2n_ptr);
+int b2n_cmp_null(b2n_ptr);
+int b2n_div(b2n_ptr, b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_div_mod(b2n_ptr, b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_div_q(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_div_r(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_exp_mod(b2n_ptr, b2n_ptr, u_int32_t, b2n_ptr);
+void b2n_init(b2n_ptr);
+void b2n_clear(b2n_ptr);
+int b2n_gcd(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_halftrace(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_lshift(b2n_ptr, b2n_ptr, unsigned int);
+int b2n_mod(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_mul(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_mul_inv(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_nadd(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_nsub(b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_print(b2n_ptr);
+int b2n_random(b2n_ptr, u_int32_t);
+int b2n_resize(b2n_ptr, unsigned int);
+int b2n_rshift(b2n_ptr, b2n_ptr, unsigned int);
+int b2n_set(b2n_ptr, b2n_ptr);
+int b2n_set_null(b2n_ptr);
+int b2n_set_str(b2n_ptr, char *);
+int b2n_set_ui(b2n_ptr, unsigned int);
+u_int32_t b2n_sigbit(b2n_ptr);
+int b2n_snprint(char *, size_t, b2n_ptr);
+int b2n_sqrt(b2n_ptr, b2n_ptr, b2n_ptr);
+int b2n_square(b2n_ptr, b2n_ptr);
+#define b2n_sub b2n_add
+int b2n_trace(b2n_ptr, b2n_ptr, b2n_ptr);
+
+#endif /* _MATH_2N_H_ */
diff --git a/keyexchange/isakmpd-20041012/math_ec2n.c b/keyexchange/isakmpd-20041012/math_ec2n.c
new file mode 100644
index 0000000..c06b37c
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/math_ec2n.c
@@ -0,0 +1,382 @@
+/* $OpenBSD: math_ec2n.c,v 1.11 2004/05/23 18:17:56 hshoexer Exp $ */
+/* $EOM: math_ec2n.c,v 1.9 1999/04/20 09:23:31 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+
+#include "sysdep.h"
+
+#include "math_2n.h"
+#include "math_ec2n.h"
+
+void
+ec2np_init(ec2np_ptr n)
+{
+ b2n_init(n->x);
+ b2n_init(n->y);
+ n->inf = 0;
+}
+
+void
+ec2np_clear(ec2np_ptr n)
+{
+ b2n_clear(n->x);
+ b2n_clear(n->y);
+}
+
+int
+ec2np_set(ec2np_ptr d, ec2np_ptr n)
+{
+ if (d == n)
+ return 0;
+
+ d->inf = n->inf;
+ if (b2n_set(d->x, n->x))
+ return -1;
+ return b2n_set(d->y, n->y);
+}
+
+/* Group */
+
+void
+ec2ng_init(ec2ng_ptr n)
+{
+ b2n_init(n->a);
+ b2n_init(n->b);
+ b2n_init(n->p);
+}
+
+void
+ec2ng_clear(ec2ng_ptr n)
+{
+ b2n_clear(n->a);
+ b2n_clear(n->b);
+ b2n_clear(n->p);
+}
+
+int
+ec2ng_set(ec2ng_ptr d, ec2ng_ptr n)
+{
+ if (b2n_set(d->a, n->a))
+ return -1;
+ if (b2n_set(d->b, n->b))
+ return -1;
+ return b2n_set(d->p, n->p);
+}
+
+/* Arithmetic functions */
+
+int
+ec2np_right(b2n_ptr n, ec2np_ptr p, ec2ng_ptr g)
+{
+ b2n_t temp;
+
+ b2n_init(temp);
+
+ /* First calc x**3 + ax**2 + b */
+ if (b2n_square(n, p->x))
+ goto fail;
+ if (b2n_mod(n, n, g->p))
+ goto fail;
+
+ if (b2n_mul(temp, g->a, n)) /* a*x**2 */
+ goto fail;
+ if (b2n_mod(temp, temp, g->p))
+ goto fail;
+
+ if (b2n_mul(n, n, p->x))/* x**3 */
+ goto fail;
+ if (b2n_mod(n, n, g->p))
+ goto fail;
+
+ if (b2n_add(n, n, temp))
+ goto fail;
+ if (b2n_add(n, n, g->b))
+ goto fail;
+
+ b2n_clear(temp);
+ return 0;
+
+fail:
+ b2n_clear(temp);
+ return -1;
+}
+
+int
+ec2np_ison(ec2np_ptr p, ec2ng_ptr g)
+{
+ int res;
+ b2n_t x, y, temp;
+
+ if (p->inf)
+ return 1;
+
+ b2n_init(x);
+ b2n_init(y);
+ b2n_init(temp);
+
+ /* First calc x**3 + ax**2 + b */
+ if (ec2np_right(x, p, g))
+ goto fail;
+
+ /* Now calc y**2 + xy */
+ if (b2n_square(y, p->y))
+ goto fail;
+ if (b2n_mod(y, y, g->p))
+ goto fail;
+
+ if (b2n_mul(temp, p->y, p->x))
+ goto fail;
+ if (b2n_mod(temp, temp, g->p))
+ goto fail;
+
+ if (b2n_add(y, y, temp))
+ goto fail;
+
+ res = !b2n_cmp(x, y);
+
+ b2n_clear(x);
+ b2n_clear(y);
+ b2n_clear(temp);
+ return res;
+
+fail:
+ b2n_clear(x);
+ b2n_clear(y);
+ b2n_clear(temp);
+ return -1;
+}
+
+int
+ec2np_find_y(ec2np_ptr p, ec2ng_ptr g)
+{
+ b2n_t right;
+
+ b2n_init(right);
+
+ if (ec2np_right(right, p, g)) /* Right sight of equation */
+ goto fail;
+ if (b2n_mul_inv(p->y, p->x, g->p))
+ goto fail;
+
+ if (b2n_square(p->y, p->y))
+ goto fail;
+ if (b2n_mod(p->y, p->y, g->p))
+ goto fail;
+
+ if (b2n_mul(right, right, p->y)) /* x^-2 * right */
+ goto fail;
+ if (b2n_mod(right, right, g->p))
+ goto fail;
+
+ if (b2n_sqrt(p->y, right, g->p)) /* Find root */
+ goto fail;
+ if (b2n_mul(p->y, p->y, p->x))
+ goto fail;
+ if (b2n_mod(p->y, p->y, g->p))
+ goto fail;
+
+ b2n_clear(right);
+ return 0;
+
+fail:
+ b2n_clear(right);
+ return -1;
+}
+
+int
+ec2np_add(ec2np_ptr d, ec2np_ptr a, ec2np_ptr b, ec2ng_ptr g)
+{
+ b2n_t lambda, temp;
+ ec2np_t pn;
+
+ /* Check for Neutral Element */
+ if (b->inf)
+ return ec2np_set(d, a);
+ if (a->inf)
+ return ec2np_set(d, b);
+
+ if (!b2n_cmp(a->x, b->x) && (b2n_cmp(a->y, b->y) ||
+ !b2n_cmp_null(a->x))) {
+ d->inf = 1;
+ if (b2n_set_null(d->x))
+ return -1;
+ return b2n_set_null(d->y);
+ }
+ b2n_init(lambda);
+ b2n_init(temp);
+ ec2np_init(pn);
+
+ if (b2n_cmp(a->x, b->x)) {
+ if (b2n_add(temp, a->x, b->x))
+ goto fail;
+ if (b2n_add(lambda, a->y, b->y))
+ goto fail;
+ if (b2n_div_mod(lambda, lambda, temp, g->p))
+ goto fail;
+
+ if (b2n_square(pn->x, lambda))
+ goto fail;
+ if (b2n_mod(pn->x, pn->x, g->p))
+ goto fail;
+
+ if (b2n_add(pn->x, pn->x, lambda))
+ goto fail;
+ if (b2n_add(pn->x, pn->x, g->a))
+ goto fail;
+ if (b2n_add(pn->x, pn->x, a->x))
+ goto fail;
+ if (b2n_add(pn->x, pn->x, b->x))
+ goto fail;
+ } else {
+ if (b2n_div_mod(lambda, b->y, b->x, g->p))
+ goto fail;
+ if (b2n_add(lambda, lambda, b->x))
+ goto fail;
+
+ if (b2n_square(pn->x, lambda))
+ goto fail;
+ if (b2n_mod(pn->x, pn->x, g->p))
+ goto fail;
+ if (b2n_add(pn->x, pn->x, lambda))
+ goto fail;
+ if (b2n_add(pn->x, pn->x, g->a))
+ goto fail;
+ }
+
+ if (b2n_add(pn->y, b->x, pn->x))
+ goto fail;
+
+ if (b2n_mul(pn->y, pn->y, lambda))
+ goto fail;
+ if (b2n_mod(pn->y, pn->y, g->p))
+ goto fail;
+
+ if (b2n_add(pn->y, pn->y, pn->x))
+ goto fail;
+ if (b2n_add(pn->y, pn->y, b->y))
+ goto fail;
+
+ EC2NP_SWAP(d, pn);
+
+ ec2np_clear(pn);
+ b2n_clear(lambda);
+ b2n_clear(temp);
+ return 0;
+
+fail:
+ ec2np_clear(pn);
+ b2n_clear(lambda);
+ b2n_clear(temp);
+ return -1;
+}
+
+int
+ec2np_mul(ec2np_ptr d, ec2np_ptr a, b2n_ptr e, ec2ng_ptr g)
+{
+ int i, j, bits, start;
+ b2n_t h, k;
+ ec2np_t q, mina;
+
+ if (!b2n_cmp_null(e)) {
+ d->inf = 1;
+ if (b2n_set_null(d->x))
+ return -1;
+ return b2n_set_null(d->y);
+ }
+ b2n_init(h);
+ b2n_init(k);
+ ec2np_init(q);
+ ec2np_init(mina);
+
+ if (ec2np_set(q, a))
+ goto fail;
+
+ /* Create the point -a. */
+ if (ec2np_set(mina, a))
+ goto fail;
+ if (b2n_add(mina->y, mina->y, mina->x))
+ goto fail;
+
+ if (b2n_set(k, e))
+ goto fail;
+ if (b2n_3mul(h, k))
+ goto fail;
+ if (b2n_resize(k, h->chunks))
+ goto fail;
+
+ /*
+ * This is low level but can not be avoided, since we have to do single
+ * bit checks on h and k.
+ */
+ bits = b2n_sigbit(h);
+ if ((bits & CHUNK_MASK) == 1) {
+ start = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS) - 2;
+ bits = CHUNK_BITS;
+ } else {
+ start = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS) - 1;
+ bits = ((bits - 1) & CHUNK_MASK);
+ }
+
+ /*
+ * This is the addition, subtraction method which is faster because
+ * we avoid one out of three additions (mean).
+ */
+ for (i = start; i >= 0; i--)
+ for (j = (i == start ? bits : CHUNK_BITS) - 1; j >= 0; j--)
+ if (i > 0 || j > 0) {
+ if (ec2np_add(q, q, q, g))
+ goto fail;
+ if ((h->limp[i] & b2n_mask[j]) && !(k->limp[i]
+ & b2n_mask[j])) {
+ if (ec2np_add(q, q, a, g))
+ goto fail;
+ } else if (!(h->limp[i] & b2n_mask[j])
+ && (k->limp[i] & b2n_mask[j]))
+ if (ec2np_add(q, q, mina, g))
+ goto fail;
+ }
+ EC2NP_SWAP(d, q);
+
+ b2n_clear(k);
+ b2n_clear(h);
+ ec2np_clear(q);
+ ec2np_clear(mina);
+ return 0;
+
+fail:
+ b2n_clear(k);
+ b2n_clear(h);
+ ec2np_clear(q);
+ ec2np_clear(mina);
+ return -1;
+}
diff --git a/keyexchange/isakmpd-20041012/math_ec2n.h b/keyexchange/isakmpd-20041012/math_ec2n.h
new file mode 100644
index 0000000..247f84a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/math_ec2n.h
@@ -0,0 +1,94 @@
+/* $OpenBSD: math_ec2n.h,v 1.7 2004/05/23 18:17:56 hshoexer Exp $ */
+/* $EOM: math_ec2n.h,v 1.4 1999/04/17 23:20:37 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MATH_EC2N_H
+#define _MATH_EC2N_H_
+
+/* Definitions for points on an elliptic curve */
+
+typedef struct {
+ int inf; /* Are we the point at infinity ? */
+ b2n_t x, y;
+} _ec2n_point;
+
+typedef _ec2n_point *ec2np_ptr;
+typedef _ec2n_point ec2np_t[1];
+
+#define EC2NP_SWAP(k,n) do \
+ { \
+ int _i_; \
+\
+ _i_ = (k)->inf; \
+ (k)->inf = (n)->inf; \
+ (n)->inf = _i_; \
+ B2N_SWAP ((k)->x, (n)->x); \
+ B2N_SWAP ((k)->y, (n)->y); \
+ } \
+while (0)
+
+void ec2np_init(ec2np_ptr);
+void ec2np_clear(ec2np_ptr);
+int ec2np_set(ec2np_ptr, ec2np_ptr);
+
+#define ec2np_set_x_ui(n, y) b2n_set_ui ((n)->x, y)
+#define ec2np_set_y_ui(n, x) b2n_set_ui ((n)->y, x)
+#define ec2np_set_x_str(n, y) b2n_set_str ((n)->x, y)
+#define ec2np_set_y_str(n, x) b2n_set_str ((n)->y, x)
+
+/* Definitions for the group to which the points to belong to. */
+
+typedef struct {
+ b2n_t a, b, p;
+} _ec2n_group;
+
+typedef _ec2n_group *ec2ng_ptr;
+typedef _ec2n_group ec2ng_t[1];
+
+void ec2ng_init(ec2ng_ptr);
+void ec2ng_clear(ec2ng_ptr);
+int ec2ng_set(ec2ng_ptr, ec2ng_ptr);
+
+#define ec2ng_set_a_ui(n, x) b2n_set_ui ((n)->a, x)
+#define ec2ng_set_b_ui(n, x) b2n_set_ui ((n)->b, x)
+#define ec2ng_set_p_ui(n, x) b2n_set_ui ((n)->p, x)
+#define ec2ng_set_a_str(n, x) b2n_set_str ((n)->a, x)
+#define ec2ng_set_b_str(n, x) b2n_set_str ((n)->b, x)
+#define ec2ng_set_p_str(n, x) b2n_set_str ((n)->p, x)
+
+/* Functions for computing on the elliptic group. */
+
+int ec2np_add(ec2np_ptr, ec2np_ptr, ec2np_ptr, ec2ng_ptr);
+int ec2np_find_y(ec2np_ptr, ec2ng_ptr);
+int ec2np_ison(ec2np_ptr, ec2ng_ptr);
+int ec2np_mul(ec2np_ptr, ec2np_ptr, b2n_ptr, ec2ng_ptr);
+int ec2np_right(b2n_ptr n, ec2np_ptr, ec2ng_ptr);
+
+#endif /* _MATH_2N_H_ */
diff --git a/keyexchange/isakmpd-20041012/math_group.c b/keyexchange/isakmpd-20041012/math_group.c
new file mode 100644
index 0000000..55f340f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/math_group.c
@@ -0,0 +1,865 @@
+/* $OpenBSD: math_group.c,v 1.23 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: math_group.c,v 1.25 2000/04/07 19:53:26 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "gmp_util.h"
+#include "log.h"
+#include "math_2n.h"
+#include "math_ec2n.h"
+#include "math_group.h"
+#include "math_mp.h"
+
+/* We do not want to export these definitions. */
+int modp_getlen(struct group *);
+void modp_getraw(struct group *, math_mp_t, u_int8_t *);
+int modp_setraw(struct group *, math_mp_t, u_int8_t *, int);
+int modp_setrandom(struct group *, math_mp_t);
+int modp_operation(struct group *, math_mp_t, math_mp_t, math_mp_t);
+
+int ec2n_getlen(struct group *);
+void ec2n_getraw(struct group *, ec2np_ptr, u_int8_t *);
+int ec2n_setraw(struct group *, ec2np_ptr, u_int8_t *, int);
+int ec2n_setrandom(struct group *, ec2np_ptr);
+int ec2n_operation(struct group *, ec2np_ptr, ec2np_ptr, ec2np_ptr);
+
+struct ec2n_group {
+ ec2np_t gen; /* Generator */
+ ec2ng_t grp;
+ ec2np_t a, b, c, d;
+};
+
+struct modp_group {
+ math_mp_t gen; /* Generator */
+ math_mp_t p; /* Prime */
+ math_mp_t a, b, c, d;
+};
+
+/*
+ * This module provides access to the operations on the specified group
+ * and is absolutly free of any cryptographic devices. This is math :-).
+ */
+
+#define OAKLEY_GRP_1 1
+#define OAKLEY_GRP_2 2
+#define OAKLEY_GRP_3 3
+#define OAKLEY_GRP_4 4
+#define OAKLEY_GRP_5 5
+#define OAKLEY_GRP_6 6
+#define OAKLEY_GRP_7 7
+#define OAKLEY_GRP_8 8
+#define OAKLEY_GRP_9 9
+#define OAKLEY_GRP_10 10
+#define OAKLEY_GRP_11 11
+#define OAKLEY_GRP_12 12
+#define OAKLEY_GRP_13 13
+#define OAKLEY_GRP_14 14
+#define OAKLEY_GRP_15 15
+#define OAKLEY_GRP_16 16
+#define OAKLEY_GRP_17 17
+#define OAKLEY_GRP_18 18
+
+/* Describe preconfigured MODP groups */
+
+/*
+ * The Generalized Number Field Sieve has an asymptotic running time
+ * of: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))), where q is the
+ * group order, e.g. q = 2**768.
+ */
+
+struct modp_dscr oakley_modp[] =
+{
+ {OAKLEY_GRP_1, 72, /* This group is insecure, only sufficient
+ * for DES */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+ {OAKLEY_GRP_2, 82, /* This group is a bit better */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+ "FFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+ {OAKLEY_GRP_5, 102,
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+ {OAKLEY_GRP_14, 135, /* 2048 bit */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+ {OAKLEY_GRP_15, 170, /* 3072 bit */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+ {OAKLEY_GRP_16, 195, /* 4096 bit */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
+ "FFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+ {OAKLEY_GRP_17, 220, /* 6144 bit */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
+ "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+ "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
+ "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+ "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
+ "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+ "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+ "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+ "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
+ "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+ "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+ {OAKLEY_GRP_18, 250, /* 8192 bit */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
+ "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+ "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
+ "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+ "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
+ "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+ "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+ "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+ "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
+ "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+ "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
+ "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
+ "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
+ "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+ "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
+ "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
+ "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
+ "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
+ "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
+ "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
+ "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
+ "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+};
+
+#ifdef USE_EC
+/* Describe preconfigured EC2N groups */
+
+/*
+ * Related collision-search methods can compute discrete logarithmns
+ * in O(sqrt(r)), r being the subgroup order.
+ */
+
+struct ec2n_dscr oakley_ec2n[] = {
+ { OAKLEY_GRP_3, 76, /* This group is also considered insecure
+ * (P1363) */
+ "0x0800000000000000000000004000000000000001",
+ "0x7b",
+ "0x00",
+ "0x7338f" },
+ { OAKLEY_GRP_4, 91,
+ "0x020000000000000000000000000000200000000000000001",
+ "0x18",
+ "0x00",
+ "0x1ee9" },
+};
+#endif /* USE_EC */
+
+/* XXX I want to get rid of the casting here. */
+struct group groups[] = {
+ {
+ MODP, OAKLEY_GRP_1, 0, &oakley_modp[0], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) modp_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw,
+ (int (*) (struct group *, void *)) modp_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) modp_operation
+ },
+ {
+ MODP, OAKLEY_GRP_2, 0, &oakley_modp[1], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) modp_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw,
+ (int (*) (struct group *, void *)) modp_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) modp_operation
+ },
+#ifdef USE_EC
+ {
+ EC2N, OAKLEY_GRP_3, 0, &oakley_ec2n[0], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) ec2n_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) ec2n_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) ec2n_setraw,
+ (int (*) (struct group *, void *)) ec2n_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) ec2n_operation
+ },
+ {
+ EC2N, OAKLEY_GRP_4, 0, &oakley_ec2n[1], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) ec2n_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) ec2n_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) ec2n_setraw,
+ (int (*) (struct group *, void *)) ec2n_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) ec2n_operation
+ },
+#endif /* USE_EC */
+ {
+ MODP, OAKLEY_GRP_5, 0, &oakley_modp[2], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) modp_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw,
+ (int (*) (struct group *, void *)) modp_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) modp_operation
+ },
+#ifdef USE_EC
+ /* XXX Higher EC2N group go here... */
+#endif /* USE_EC */
+ /* XXX group 6 to 13 are not yet defined (draft-ike-ecc) */
+ {
+ NOTYET, OAKLEY_GRP_6, 0, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ {
+ NOTYET, OAKLEY_GRP_7, 0, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ {
+ NOTYET, OAKLEY_GRP_8, 0, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ {
+ NOTYET, OAKLEY_GRP_9, 0, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ {
+ NOTYET, OAKLEY_GRP_10, 0, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ {
+ NOTYET, OAKLEY_GRP_11, 0, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ {
+ NOTYET, OAKLEY_GRP_12, 0, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ {
+ NOTYET, OAKLEY_GRP_13, 0, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ {
+ MODP, OAKLEY_GRP_14, 0, &oakley_modp[3], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) modp_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw,
+ (int (*) (struct group *, void *)) modp_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) modp_operation
+ },
+ {
+ MODP, OAKLEY_GRP_15, 0, &oakley_modp[4], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) modp_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw,
+ (int (*) (struct group *, void *)) modp_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) modp_operation
+ },
+ {
+ MODP, OAKLEY_GRP_16, 0, &oakley_modp[5], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) modp_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw,
+ (int (*) (struct group *, void *)) modp_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) modp_operation
+ },
+ {
+ MODP, OAKLEY_GRP_17, 0, &oakley_modp[6], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) modp_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw,
+ (int (*) (struct group *, void *)) modp_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) modp_operation
+ },
+ {
+ MODP, OAKLEY_GRP_18, 0, &oakley_modp[7], 0, 0, 0, 0, 0,
+ (int (*) (struct group *)) modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *)) modp_getraw,
+ (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw,
+ (int (*) (struct group *, void *)) modp_setrandom,
+ (int (*) (struct group *, void *, void *, void *)) modp_operation
+ },
+};
+
+/*
+ * Initialize the group structure for later use,
+ * this is done by converting the values given in the describtion
+ * and converting them to their native representation.
+ */
+void
+group_init(void)
+{
+ int i;
+
+ for (i = sizeof(groups) / sizeof(groups[0]) - 1; i >= 0; i--)
+ switch (groups[i].type) {
+#ifdef USE_EC
+ case EC2N: /* Initialize an Elliptic Curve over GF(2**n) */
+ ec2n_init(&groups[i]);
+ break;
+#endif
+
+ case MODP: /* Initialize an over GF(p) */
+ modp_init(&groups[i]);
+ break;
+
+ case NOTYET: /* Not yet assigned, drop silently */
+ break;
+
+ default:
+ log_print("Unknown group type %d at index %d in "
+ "group_init().", groups[i].type, i);
+ break;
+ }
+}
+
+struct group *
+group_get(u_int32_t id)
+{
+ struct group *new, *clone;
+
+ if (id < 1 || id > (sizeof(groups) / sizeof(groups[0]))) {
+ log_print("group_get: group ID (%u) out of range", id);
+ return 0;
+ }
+ clone = &groups[id - 1];
+
+ new = malloc(sizeof *new);
+ if (!new) {
+ log_error("group_get: malloc (%lu) failed",
+ (unsigned long)sizeof *new);
+ return 0;
+ }
+ switch (clone->type) {
+#ifdef USE_EC
+ case EC2N:
+ new = ec2n_clone(new, clone);
+ break;
+#endif
+ case MODP:
+ new = modp_clone(new, clone);
+ break;
+ default:
+ log_print("group_get: unknown group type %d", clone->type);
+ free(new);
+ return 0;
+ }
+ LOG_DBG((LOG_MISC, 70, "group_get: returning %p of group %d", new,
+ new->id));
+ return new;
+}
+
+void
+group_free(struct group *grp)
+{
+ switch (grp->type) {
+#ifdef USE_EC
+ case EC2N:
+ ec2n_free(grp);
+ break;
+#endif
+ case MODP:
+ modp_free(grp);
+ break;
+ default:
+ log_print("group_free: unknown group type %d", grp->type);
+ break;
+ }
+ free(grp);
+}
+
+struct group *
+modp_clone(struct group *new, struct group *clone)
+{
+ struct modp_group *new_grp, *clone_grp = clone->group;
+
+ new_grp = malloc(sizeof *new_grp);
+ if (!new_grp) {
+ log_print("modp_clone: malloc (%lu) failed",
+ (unsigned long)sizeof *new_grp);
+ free(new);
+ return 0;
+ }
+ memcpy(new, clone, sizeof(struct group));
+
+ new->group = new_grp;
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ mpz_init_set(new_grp->p, clone_grp->p);
+ mpz_init_set(new_grp->gen, clone_grp->gen);
+
+ mpz_init(new_grp->a);
+ mpz_init(new_grp->b);
+ mpz_init(new_grp->c);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ new_grp->p = BN_dup(clone_grp->p);
+ new_grp->gen = BN_dup(clone_grp->gen);
+
+ new_grp->a = BN_new();
+ new_grp->b = BN_new();
+ new_grp->c = BN_new();
+#endif
+
+ new->gen = new_grp->gen;
+ new->a = new_grp->a;
+ new->b = new_grp->b;
+ new->c = new_grp->c;
+
+ return new;
+}
+
+void
+modp_free(struct group *old)
+{
+ struct modp_group *grp = old->group;
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ mpz_clear(grp->p);
+ mpz_clear(grp->gen);
+ mpz_clear(grp->a);
+ mpz_clear(grp->b);
+ mpz_clear(grp->c);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ BN_clear_free(grp->p);
+ BN_clear_free(grp->gen);
+ BN_clear_free(grp->a);
+ BN_clear_free(grp->b);
+ BN_clear_free(grp->c);
+#endif
+
+ free(grp);
+}
+
+void
+modp_init(struct group *group)
+{
+ struct modp_dscr *dscr = (struct modp_dscr *)group->group;
+ struct modp_group *grp;
+
+ grp = malloc(sizeof *grp);
+ if (!grp)
+ log_fatal("modp_init: malloc (%lu) failed",
+ (unsigned long)sizeof *grp);
+
+ group->bits = dscr->bits;
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ mpz_init_set_str(grp->p, dscr->prime, 0);
+ mpz_init_set_str(grp->gen, dscr->gen, 0);
+
+ mpz_init(grp->a);
+ mpz_init(grp->b);
+ mpz_init(grp->c);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ grp->p = BN_new();
+ BN_hex2bn(&grp->p, dscr->prime + 2);
+ grp->gen = BN_new();
+ BN_hex2bn(&grp->gen, dscr->gen + 2);
+
+ grp->a = BN_new();
+ grp->b = BN_new();
+ grp->c = BN_new();
+#endif
+
+ group->gen = grp->gen;
+ group->a = grp->a;
+ group->b = grp->b;
+ group->c = grp->c;
+
+ group->group = grp;
+}
+
+#ifdef USE_EC
+struct group *
+ec2n_clone(struct group *new, struct group *clone)
+{
+ struct ec2n_group *new_grp, *clone_grp = clone->group;
+
+ new_grp = malloc(sizeof *new_grp);
+ if (!new_grp) {
+ log_error("ec2n_clone: malloc (%lu) failed",
+ (unsigned long)sizeof *new_grp);
+ free(new);
+ return 0;
+ }
+ memcpy(new, clone, sizeof(struct group));
+
+ new->group = new_grp;
+ ec2ng_init(new_grp->grp);
+ ec2np_init(new_grp->gen);
+ ec2np_init(new_grp->a);
+ ec2np_init(new_grp->b);
+ ec2np_init(new_grp->c);
+
+ if (ec2ng_set(new_grp->grp, clone_grp->grp))
+ goto fail;
+ if (ec2np_set(new_grp->gen, clone_grp->gen))
+ goto fail;
+
+ new->gen = new_grp->gen;
+ new->a = new_grp->a;
+ new->b = new_grp->b;
+ new->c = new_grp->c;
+ new->d = ((ec2np_ptr) new->a)->x;
+
+ return new;
+
+fail:
+ ec2ng_clear(new_grp->grp);
+ ec2np_clear(new_grp->gen);
+ ec2np_clear(new_grp->a);
+ ec2np_clear(new_grp->b);
+ ec2np_clear(new_grp->c);
+ free(new_grp);
+ free(new);
+ return 0;
+}
+
+void
+ec2n_free(struct group *old)
+{
+ struct ec2n_group *grp = old->group;
+
+ ec2ng_clear(grp->grp);
+ ec2np_clear(grp->gen);
+ ec2np_clear(grp->a);
+ ec2np_clear(grp->b);
+ ec2np_clear(grp->c);
+
+ free(grp);
+}
+
+void
+ec2n_init(struct group *group)
+{
+ struct ec2n_dscr *dscr = (struct ec2n_dscr *)group->group;
+ struct ec2n_group *grp;
+
+ grp = malloc(sizeof *grp);
+ if (!grp)
+ log_fatal("ec2n_init: malloc (%lu) failed",
+ (unsigned long)sizeof *grp);
+
+ group->bits = dscr->bits;
+
+ ec2ng_init(grp->grp);
+ ec2np_init(grp->gen);
+ ec2np_init(grp->a);
+ ec2np_init(grp->b);
+ ec2np_init(grp->c);
+
+ if (ec2ng_set_p_str(grp->grp, dscr->polynomial))
+ goto fail;
+ grp->grp->p->bits = b2n_sigbit(grp->grp->p);
+ if (ec2ng_set_a_str(grp->grp, dscr->a))
+ goto fail;
+ if (ec2ng_set_b_str(grp->grp, dscr->b))
+ goto fail;
+
+ if (ec2np_set_x_str(grp->gen, dscr->gen_x))
+ goto fail;
+ if (ec2np_find_y(grp->gen, grp->grp))
+ goto fail;
+
+ /* Sanity check */
+ if (!ec2np_ison(grp->gen, grp->grp))
+ log_fatal("ec2n_init: generator is not on curve");
+
+ group->gen = grp->gen;
+ group->a = grp->a;
+ group->b = grp->b;
+ group->c = grp->c;
+ group->d = ((ec2np_ptr) group->a)->x;
+
+ group->group = grp;
+ return;
+
+fail:
+ log_fatal("ec2n_init: general failure");
+}
+#endif /* USE_EC */
+
+int
+modp_getlen(struct group *group)
+{
+ struct modp_group *grp = (struct modp_group *)group->group;
+
+ return mpz_sizeinoctets(grp->p);
+}
+
+void
+modp_getraw(struct group *grp, math_mp_t v, u_int8_t *d)
+{
+ mpz_getraw(d, v, grp->getlen(grp));
+}
+
+int
+modp_setraw(struct group *grp, math_mp_t d, u_int8_t *s, int l)
+{
+ mpz_setraw(d, s, l);
+ return 0;
+}
+
+int
+modp_setrandom(struct group *grp, math_mp_t d)
+{
+ int i, l = grp->getlen(grp);
+ u_int32_t tmp = 0;
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ mpz_set_ui(d, 0);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ BN_set_word(d, 0);
+#endif
+
+ for (i = 0; i < l; i++) {
+ if (i % 4)
+ tmp = sysdep_random();
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ mpz_mul_2exp(d, d, 8);
+ mpz_add_ui(d, d, tmp & 0xFF);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ BN_lshift(d, d, 8);
+ BN_add_word(d, tmp & 0xFF);
+#endif
+ tmp >>= 8;
+ }
+ return 0;
+}
+
+int
+modp_operation(struct group *group, math_mp_t d, math_mp_t a, math_mp_t e)
+{
+ struct modp_group *grp = (struct modp_group *)group->group;
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+ mpz_powm(d, a, e, grp->p);
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+ BN_CTX *ctx = BN_CTX_new();
+ BN_mod_exp(d, a, e, grp->p, ctx);
+ BN_CTX_free(ctx);
+#endif
+ return 0;
+}
+
+#ifdef USE_EC
+int
+ec2n_getlen(struct group *group)
+{
+ struct ec2n_group *grp = (struct ec2n_group *)group->group;
+ int bits = b2n_sigbit(grp->grp->p) - 1;
+
+ return (7 + bits) >> 3;
+}
+
+void
+ec2n_getraw(struct group *group, ec2np_ptr xo, u_int8_t *e)
+{
+ struct ec2n_group *grp = (struct ec2n_group *) group->group;
+ int chunks, bytes, i, j;
+ b2n_ptr x = xo->x;
+ CHUNK_TYPE tmp;
+
+ bytes = b2n_sigbit(grp->grp->p) - 1;
+ chunks = (CHUNK_MASK + bytes) >> CHUNK_SHIFTS;
+ bytes = ((7 + (bytes & CHUNK_MASK)) >> 3);
+
+ for (i = chunks - 1; i >= 0; i--) {
+ tmp = (i >= x->chunks ? 0 : x->limp[i]);
+ for (j = (i == chunks - 1 ? bytes : CHUNK_BYTES) - 1; j >= 0;
+ j--) {
+ e[j] = tmp & 0xff;
+ tmp >>= 8;
+ }
+ e += (i == chunks - 1 ? bytes : CHUNK_BYTES);
+ }
+}
+
+int
+ec2n_setraw(struct group *grp, ec2np_ptr out, u_int8_t *s, int l)
+{
+ int len, bytes, i, j;
+ b2n_ptr outx = out->x;
+ CHUNK_TYPE tmp;
+
+ len = (CHUNK_BYTES - 1 + l) / CHUNK_BYTES;
+ if (b2n_resize(outx, len))
+ return -1;
+
+ bytes = ((l - 1) % CHUNK_BYTES) + 1;
+
+ for (i = len - 1; i >= 0; i--) {
+ tmp = 0;
+ for (j = (i == len - 1 ? bytes : CHUNK_BYTES); j > 0; j--) {
+ tmp <<= 8;
+ tmp |= *s++;
+ }
+ outx->limp[i] = tmp;
+ }
+ return 0;
+}
+
+int
+ec2n_setrandom(struct group *group, ec2np_ptr x)
+{
+ b2n_ptr d = x->x;
+ struct ec2n_group *grp = (struct ec2n_group *) group->group;
+
+ return b2n_random(d, b2n_sigbit(grp->grp->p) - 1);
+}
+
+/*
+ * This is an attempt at operation abstraction. It can happen
+ * that we need to initialize the y variable for the operation
+ * to proceed correctly. When this is the case operation has
+ * to supply the variable 'a' with the chunks of the Y cooridnate
+ * set to zero.
+ */
+int
+ec2n_operation(struct group *grp, ec2np_ptr d, ec2np_ptr a, ec2np_ptr e)
+{
+ b2n_ptr ex = e->x;
+ struct ec2n_group *group = (struct ec2n_group *)grp->group;
+
+ if (a->y->chunks == 0)
+ if (ec2np_find_y(a, group->grp))
+ return -1;
+
+ return ec2np_mul(d, a, ex, group->grp);
+}
+#endif /* USE_EC */
diff --git a/keyexchange/isakmpd-20041012/math_group.h b/keyexchange/isakmpd-20041012/math_group.h
new file mode 100644
index 0000000..d5a19bc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/math_group.h
@@ -0,0 +1,94 @@
+/* $OpenBSD: math_group.h,v 1.10 2004/04/15 18:39:26 deraadt Exp $ */
+/* $EOM: math_group.h,v 1.7 1999/04/17 23:20:40 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MATH_GROUP_H_
+#define _MATH_GROUP_H_
+
+enum groups {
+ MODP, /* F_p, Z modulo a prime */
+ EC2N, /* Elliptic Curve over the Field GF(2**N) */
+ ECP, /* Elliptic Curve over the Field Z_p */
+ NOTYET /* Not yet assigned */
+};
+
+/*
+ * The group on which diffie hellmann calculations are done.
+ */
+
+struct group {
+ enum groups type;
+ int id; /* Group ID */
+ int bits; /* Number of key bits provided by this group */
+ void *group;
+ void *a, *b, *c, *d;
+ void *gen; /* Group Generator */
+ int (*getlen) (struct group *);
+ void (*getraw) (struct group *, void *, u_int8_t *);
+ int (*setraw) (struct group *, void *, u_int8_t *, int);
+ int (*setrandom) (struct group *, void *);
+ int (*operation) (struct group *, void *, void *, void *);
+};
+
+/* Description of an Elliptic Group over GF(2**n) for Boot-Strapping */
+
+struct ec2n_dscr {
+ int id;
+ int bits; /* Key Bits provided by this group */
+ char *polynomial; /* Irreduceable polynomial */
+ char *gen_x; /* X - Coord. of Generator */
+ char *a, *b; /* Curve Parameters */
+};
+
+/* Description of F_p for Boot-Strapping */
+
+struct modp_dscr {
+ int id;
+ int bits; /* Key Bits provided by this group */
+ char *prime; /* Prime */
+ char *gen; /* Generator */
+};
+
+/* Prototypes */
+
+void group_init(void);
+void group_free(struct group *);
+struct group *group_get(u_int32_t);
+
+void ec2n_free(struct group *);
+struct group *ec2n_clone(struct group *, struct group *);
+void ec2n_init(struct group *);
+
+void modp_free(struct group *);
+struct group *modp_clone(struct group *, struct group *);
+void modp_init(struct group *);
+
+#endif /* _MATH_GROUP_H_ */
diff --git a/keyexchange/isakmpd-20041012/math_mp.h b/keyexchange/isakmpd-20041012/math_mp.h
new file mode 100644
index 0000000..ed554fc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/math_mp.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: math_mp.h,v 1.6 2004/04/15 18:39:26 deraadt Exp $ */
+/* $EOM: math_mp.h,v 1.4 2000/09/16 09:41:43 ho Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MATH_MP_H_
+#define _MATH_MP_H_
+
+#define MP_FLAVOUR_GMP 1
+#define MP_FLAVOUR_OPENSSL 2
+
+#if MP_FLAVOUR == MP_FLAVOUR_GMP
+
+#include <gmp.h>
+
+#define math_mp_t mpz_t
+
+#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL
+
+#include <openssl/bn.h>
+
+typedef BIGNUM *math_mp_t;
+
+#else
+
+#error "No multiprecision math library chosen."
+
+#endif
+
+#endif /* _MATH_MP_H_ */
diff --git a/keyexchange/isakmpd-20041012/message.c b/keyexchange/isakmpd-20041012/message.c
new file mode 100644
index 0000000..9259e2d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/message.c
@@ -0,0 +1,2530 @@
+/* $OpenBSD: message.c,v 1.89 2004/09/17 13:45:02 ho Exp $ */
+/* $EOM: message.c,v 1.156 2000/10/10 12:36:39 provos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "cert.h"
+#include "constants.h"
+#include "crypto.h"
+#include "doi.h"
+#ifdef USE_DPD
+#include "dpd.h"
+#endif
+#include "exchange.h"
+#include "field.h"
+#include "hash.h"
+#include "ipsec.h"
+#include "ipsec_num.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#if defined (USE_NAT_TRAVERSAL)
+#include "nat_traversal.h"
+#endif
+#include "prf.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+#include "virtual.h"
+
+#ifdef __GNUC__
+#define INLINE __inline
+#else
+#define INLINE
+#endif
+
+/* A local set datatype, coincidentally fd_set suits our purpose fine. */
+typedef fd_set set;
+#define ISSET FD_ISSET
+#define SET FD_SET
+#define ZERO FD_ZERO
+
+static int message_check_duplicate(struct message *);
+static int message_encrypt(struct message *);
+static int message_index_payload(struct message *, struct payload *,
+ u_int8_t ,u_int8_t *);
+static int message_parse_transform(struct message *, struct payload *,
+ u_int8_t, u_int8_t *);
+static u_int16_t message_payload_sz(u_int8_t);
+static int message_validate_attribute(struct message *, struct payload *);
+static int message_validate_cert(struct message *, struct payload *);
+static int message_validate_cert_req(struct message *, struct payload *);
+static int message_validate_delete(struct message *, struct payload *);
+static int message_validate_hash(struct message *, struct payload *);
+static int message_validate_id(struct message *, struct payload *);
+static int message_validate_key_exch(struct message *, struct payload *);
+static int message_validate_nat_d(struct message *, struct payload *);
+static int message_validate_nat_oa(struct message *, struct payload *);
+static int message_validate_nonce(struct message *, struct payload *);
+static int message_validate_notify(struct message *, struct payload *);
+static int message_validate_proposal(struct message *, struct payload *);
+static int message_validate_sa(struct message *, struct payload *);
+static int message_validate_sig(struct message *, struct payload *);
+static int message_validate_transform(struct message *, struct payload *);
+static int message_validate_vendor(struct message *, struct payload *);
+
+static void message_packet_log(struct message *);
+
+static int (*message_validate_payload[])(struct message *, struct payload *) =
+{
+ message_validate_sa, message_validate_proposal,
+ message_validate_transform, message_validate_key_exch,
+ message_validate_id, message_validate_cert, message_validate_cert_req,
+ message_validate_hash, message_validate_sig, message_validate_nonce,
+ message_validate_notify, message_validate_delete,
+ message_validate_vendor, message_validate_attribute,
+ message_validate_nat_d, message_validate_nat_oa,
+ message_validate_nat_d, message_validate_nat_oa
+};
+
+static struct field *fields[] = {
+ isakmp_sa_fld, isakmp_prop_fld, isakmp_transform_fld, isakmp_ke_fld,
+ isakmp_id_fld, isakmp_cert_fld, isakmp_certreq_fld, isakmp_hash_fld,
+ isakmp_sig_fld, isakmp_nonce_fld, isakmp_notify_fld, isakmp_delete_fld,
+ isakmp_vendor_fld, isakmp_attribute_fld, isakmp_nat_d_fld,
+ isakmp_nat_oa_fld, isakmp_nat_d_fld, isakmp_nat_oa_fld
+};
+
+/*
+ * These maps are used for indexing the payloads in msg->payloads[i].
+ * payload_revmap should be updated if the payloads in isakmp_num.cst change.
+ * payload_map is populated during startup by message_init().
+ */
+static u_int8_t payload_revmap[] = {
+ ISAKMP_PAYLOAD_NONE, ISAKMP_PAYLOAD_SA, ISAKMP_PAYLOAD_PROPOSAL,
+ ISAKMP_PAYLOAD_TRANSFORM, ISAKMP_PAYLOAD_KEY_EXCH, ISAKMP_PAYLOAD_ID,
+ ISAKMP_PAYLOAD_CERT, ISAKMP_PAYLOAD_CERT_REQ, ISAKMP_PAYLOAD_HASH,
+ ISAKMP_PAYLOAD_SIG, ISAKMP_PAYLOAD_NONCE, ISAKMP_PAYLOAD_NOTIFY,
+ ISAKMP_PAYLOAD_DELETE, ISAKMP_PAYLOAD_VENDOR, ISAKMP_PAYLOAD_ATTRIBUTE,
+#ifdef notyet
+ ISAKMP_PAYLOAD_SAK, ISAKMP_PAYLOAD_SAT, ISAKMP_PAYLOAD_KD,
+ ISAKMP_PAYLOAD_SEQ, ISAKMP_PAYLOAD_POP
+#endif
+ ISAKMP_PAYLOAD_NAT_D, ISAKMP_PAYLOAD_NAT_OA,
+ ISAKMP_PAYLOAD_NAT_D_DRAFT, ISAKMP_PAYLOAD_NAT_OA_DRAFT
+};
+
+static u_int8_t payload_map[256];
+u_int8_t payload_index_max;
+
+/*
+ * Fields used for checking monotonic increasing of proposal and transform
+ * numbers.
+ */
+static u_int8_t *last_sa = 0;
+static u_int32_t last_prop_no;
+static u_int8_t *last_prop = 0;
+static u_int32_t last_xf_no;
+
+/*
+ * Allocate a message structure bound to transport T, and with a first
+ * segment buffer sized SZ, copied from BUF if given.
+ */
+struct message *
+message_alloc(struct transport *t, u_int8_t *buf, size_t sz)
+{
+ struct message *msg;
+ int i;
+
+ /*
+ * We use calloc(3) because it zeroes the structure which we rely on in
+ * message_free when determining what sub-allocations to free.
+ */
+ msg = (struct message *)calloc(1, sizeof *msg);
+ if (!msg)
+ return 0;
+ msg->iov = calloc(1, sizeof *msg->iov);
+ if (!msg->iov) {
+ message_free(msg);
+ return 0;
+ }
+ msg->iov[0].iov_len = sz;
+ msg->iov[0].iov_base = malloc(sz);
+ if (!msg->iov[0].iov_base) {
+ message_free(msg);
+ return 0;
+ }
+ msg->iovlen = 1;
+ if (buf)
+ memcpy(msg->iov[0].iov_base, buf, sz);
+ msg->nextp = (u_int8_t *)msg->iov[0].iov_base +
+ ISAKMP_HDR_NEXT_PAYLOAD_OFF;
+ msg->transport = t;
+ transport_reference(t);
+ msg->payload = (struct payload_head *)calloc(payload_index_max,
+ sizeof *msg->payload);
+ if (!msg->payload) {
+ message_free(msg);
+ return 0;
+ }
+ for (i = 0; i < payload_index_max; i++)
+ TAILQ_INIT(&msg->payload[i]);
+ TAILQ_INIT(&msg->post_send);
+ LOG_DBG((LOG_MESSAGE, 90, "message_alloc: allocated %p", msg));
+ return msg;
+}
+
+/*
+ * Allocate a message suitable for a reply to MSG. Just allocate an empty
+ * ISAKMP header as the first segment.
+ */
+struct message *
+message_alloc_reply(struct message *msg)
+{
+ struct message *reply;
+
+ reply = message_alloc(msg->transport, 0, ISAKMP_HDR_SZ);
+ reply->exchange = msg->exchange;
+ reply->isakmp_sa = msg->isakmp_sa;
+ if (msg->isakmp_sa)
+ sa_reference(msg->isakmp_sa);
+ return reply;
+}
+
+/* Free up all resources used by the MSG message. */
+void
+message_free(struct message *msg)
+{
+ u_int32_t i;
+ struct payload *payload, *next;
+
+ LOG_DBG((LOG_MESSAGE, 20, "message_free: freeing %p", msg));
+ if (!msg)
+ return;
+ if (msg->orig && msg->orig != (u_int8_t *) msg->iov[0].iov_base)
+ free(msg->orig);
+ if (msg->iov) {
+ for (i = 0; i < msg->iovlen; i++)
+ if (msg->iov[i].iov_base)
+ free(msg->iov[i].iov_base);
+ free(msg->iov);
+ }
+ if (msg->retrans)
+ timer_remove_event(msg->retrans);
+ if (msg->payload) {
+ for (i = 0; i < payload_index_max; i++)
+ for (payload = payload_first(msg, i); payload;
+ payload = next) {
+ next = TAILQ_NEXT(payload, link);
+ free(payload);
+ }
+ free(msg->payload);
+ }
+ while (TAILQ_FIRST(&msg->post_send) != 0)
+ TAILQ_REMOVE(&msg->post_send, TAILQ_FIRST(&msg->post_send),
+ link);
+
+ /* If we are on the send queue, remove us from there. */
+ if (msg->flags & MSG_IN_TRANSIT)
+ TAILQ_REMOVE(msg->transport->vtbl->get_queue(msg), msg, link);
+
+ if (msg->transport)
+ transport_release(msg->transport);
+
+ if (msg->isakmp_sa)
+ sa_release(msg->isakmp_sa);
+
+ free(msg);
+}
+
+/*
+ * Generic ISAKMP parser.
+ * MSG is the ISAKMP message to be parsed. NEXT is the type of the first
+ * payload to be parsed, and it's pointed to by BUF. ACCEPTED_PAYLOADS
+ * tells what payloads are accepted and FUNC is a pointer to a function
+ * to be called for each payload found. Returns the total length of the
+ * parsed payloads.
+ */
+static int
+message_parse_payloads(struct message *msg, struct payload *p, u_int8_t next,
+ u_int8_t *buf, set *accepted_payloads, int (*func)(struct message *,
+ struct payload *, u_int8_t, u_int8_t *))
+{
+ u_int8_t payload;
+ u_int16_t len;
+ int sz = 0;
+
+ do {
+ LOG_DBG((LOG_MESSAGE, 50,
+ "message_parse_payloads: offset %ld payload %s",
+ (long)(buf - (u_int8_t *) msg->iov[0].iov_base),
+ constant_name(isakmp_payload_cst, next)));
+
+ /* Does this payload's header fit? */
+ if (buf + ISAKMP_GEN_SZ > (u_int8_t *)msg->iov[0].iov_base +
+ msg->iov[0].iov_len) {
+ log_print("message_parse_payloads: short message");
+ message_drop(msg,
+ ISAKMP_NOTIFY_UNEQUAL_PAYLOAD_LENGTHS, 0, 1, 1);
+ return -1;
+ }
+ /* Ponder on the payload that is at BUF... */
+ payload = next;
+
+ /* Look at the next payload's type. */
+ next = GET_ISAKMP_GEN_NEXT_PAYLOAD(buf);
+ if (next >= ISAKMP_PAYLOAD_RESERVED_MIN &&
+ next <= ISAKMP_PAYLOAD_RESERVED_MAX) {
+ log_print("message_parse_payloads: invalid next "
+ "payload type %s in payload of type %d",
+ constant_name(isakmp_payload_cst, next), payload);
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE,
+ 0, 1, 1);
+ return -1;
+ }
+ /* Reserved fields in ISAKMP messages should be zero. */
+ if (GET_ISAKMP_GEN_RESERVED(buf) != 0) {
+ log_print("message_parse_payloads: reserved field "
+ "non-zero: %x", GET_ISAKMP_GEN_RESERVED(buf));
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
+ 0, 1, 1);
+ return -1;
+ }
+ /*
+ * Decode and validate the payload length field.
+ */
+ len = GET_ISAKMP_GEN_LENGTH(buf);
+
+ if (message_payload_sz(payload) == 0) {
+ log_print("message_parse_payloads: unknown minimum "
+ "payload size for payload type %s",
+ constant_name(isakmp_payload_cst, payload));
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
+ 0, 1, 1);
+ return -1;
+ }
+ if (len < message_payload_sz(payload)) {
+ log_print("message_parse_payloads: payload too "
+ "short: %u", len);
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
+ 0, 1, 1);
+ return -1;
+ }
+ if (buf + len > (u_int8_t *)msg->iov[0].iov_base +
+ msg->iov[0].iov_len) {
+ log_print("message_parse_payloads: payload too "
+ "long: %u", len);
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
+ 0, 1, 1);
+ return -1;
+ }
+ /* Ignore most private payloads. */
+ if (next >= ISAKMP_PAYLOAD_PRIVATE_MIN &&
+ next != ISAKMP_PAYLOAD_NAT_D_DRAFT &&
+ next != ISAKMP_PAYLOAD_NAT_OA_DRAFT) {
+ LOG_DBG((LOG_MESSAGE, 30, "message_parse_payloads: "
+ "private next payload type %s in payload of "
+ "type %d ignored",
+ constant_name(isakmp_payload_cst, next), payload));
+ goto next_payload;
+ }
+ /*
+ * Check if the current payload is one of the accepted ones at
+ * this stage.
+ */
+ if (!ISSET(payload, accepted_payloads)) {
+ log_print("message_parse_payloads: payload type %s "
+ "unexpected", constant_name(isakmp_payload_cst,
+ payload));
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE,
+ 0, 1, 1);
+ return -1;
+ }
+ /* Call the payload handler specified by the caller. */
+ if (func(msg, p, payload, buf))
+ return -1;
+
+next_payload:
+ /* Advance to next payload. */
+ buf += len;
+ sz += len;
+ }
+ while (next != ISAKMP_PAYLOAD_NONE);
+ return sz;
+}
+
+/*
+ * Parse a proposal payload found in message MSG. PAYLOAD is always
+ * ISAKMP_PAYLOAD_PROPOSAL and ignored in here. It's needed as the API for
+ * message_parse_payloads requires it. BUF points to the proposal's
+ * generic payload header.
+ */
+static int
+message_parse_proposal(struct message *msg, struct payload *p,
+ u_int8_t payload, u_int8_t *buf)
+{
+ set payload_set;
+
+ /* Put the proposal into the proposal bucket. */
+ message_index_payload(msg, p, payload, buf);
+
+ ZERO(&payload_set);
+ SET(payload_revmap[ISAKMP_PAYLOAD_TRANSFORM], &payload_set);
+ if (message_parse_payloads(msg,
+ payload_last(msg, ISAKMP_PAYLOAD_PROPOSAL),
+ ISAKMP_PAYLOAD_TRANSFORM, buf + ISAKMP_PROP_SPI_OFF +
+ GET_ISAKMP_PROP_SPI_SZ(buf), &payload_set, message_parse_transform)
+ == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+message_parse_transform(struct message *msg, struct payload *p,
+ u_int8_t payload, u_int8_t *buf)
+{
+ /* Put the transform into the transform bucket. */
+ message_index_payload(msg, p, payload, buf);
+
+ LOG_DBG((LOG_MESSAGE, 50, "Transform %d's attributes",
+ GET_ISAKMP_TRANSFORM_NO(buf)));
+#ifdef USE_DEBUG
+ attribute_map(buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH(buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ msg->exchange->doi->debug_attribute, msg);
+#endif
+
+ return 0;
+}
+
+/* Check payloads for their required minimum size. */
+static u_int16_t
+message_payload_sz(u_int8_t payload)
+{
+ switch (payload) {
+ case ISAKMP_PAYLOAD_SA:
+ return ISAKMP_SA_SZ;
+ case ISAKMP_PAYLOAD_PROPOSAL:
+ return ISAKMP_PROP_SZ;
+ case ISAKMP_PAYLOAD_TRANSFORM:
+ return ISAKMP_TRANSFORM_SZ;
+ case ISAKMP_PAYLOAD_KEY_EXCH:
+ return ISAKMP_KE_SZ;
+ case ISAKMP_PAYLOAD_ID:
+ return ISAKMP_ID_SZ;
+ case ISAKMP_PAYLOAD_CERT:
+ return ISAKMP_CERT_SZ;
+ case ISAKMP_PAYLOAD_CERT_REQ:
+ return ISAKMP_CERTREQ_SZ;
+ case ISAKMP_PAYLOAD_HASH:
+ return ISAKMP_HASH_SZ;
+ case ISAKMP_PAYLOAD_SIG:
+ return ISAKMP_SIG_SZ;
+ case ISAKMP_PAYLOAD_NONCE:
+ return ISAKMP_NONCE_SZ;
+ case ISAKMP_PAYLOAD_NOTIFY:
+ return ISAKMP_NOTIFY_SZ;
+ case ISAKMP_PAYLOAD_DELETE:
+ return ISAKMP_DELETE_SZ;
+ case ISAKMP_PAYLOAD_VENDOR:
+ return ISAKMP_VENDOR_SZ;
+ case ISAKMP_PAYLOAD_ATTRIBUTE:
+ return ISAKMP_ATTRIBUTE_SZ;
+#if defined (USE_NAT_TRAVERSAL)
+ case ISAKMP_PAYLOAD_NAT_D:
+ case ISAKMP_PAYLOAD_NAT_D_DRAFT:
+ return ISAKMP_NAT_D_SZ;
+ case ISAKMP_PAYLOAD_NAT_OA:
+ case ISAKMP_PAYLOAD_NAT_OA_DRAFT:
+ return ISAKMP_NAT_OA_SZ;
+#endif
+ /* Not yet supported and any other unknown payloads. */
+ case ISAKMP_PAYLOAD_SAK:
+ case ISAKMP_PAYLOAD_SAT:
+ case ISAKMP_PAYLOAD_KD:
+ case ISAKMP_PAYLOAD_SEQ:
+ case ISAKMP_PAYLOAD_POP:
+ default:
+ return 0;
+ }
+}
+
+/* Validate the attribute payload P in message MSG. */
+static int
+message_validate_attribute(struct message *msg, struct payload *p)
+{
+#ifdef USE_ISAKMP_CFG
+ /* If we don't have an exchange yet, create one. */
+ if (!msg->exchange) {
+ if (zero_test((u_int8_t *) msg->iov[0].iov_base +
+ ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN))
+ msg->exchange = exchange_setup_p1(msg,
+ IPSEC_DOI_IPSEC);
+ else
+ msg->exchange = exchange_setup_p2(msg,
+ IPSEC_DOI_IPSEC);
+ if (!msg->exchange) {
+ log_print("message_validate_attribute: can not "
+ "create exchange");
+ message_free(msg);
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+/* Validate the certificate payload P in message MSG. */
+static int
+message_validate_cert(struct message *msg, struct payload *p)
+{
+ if (GET_ISAKMP_CERT_ENCODING(p->p) >= ISAKMP_CERTENC_RESERVED_MIN) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_CERT_ENCODING, 0, 1,
+ 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the certificate request payload P in message MSG. */
+static int
+message_validate_cert_req(struct message *msg, struct payload *p)
+{
+ struct cert_handler *cert;
+ size_t len =
+ GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_CERTREQ_AUTHORITY_OFF;
+
+ if (GET_ISAKMP_CERTREQ_TYPE(p->p) >= ISAKMP_CERTENC_RESERVED_MIN) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_CERT_ENCODING, 0, 1,
+ 1);
+ return -1;
+ }
+ /*
+ * Check the certificate types we support and if an acceptable
+ * authority is included in the payload check if it can be decoded
+ */
+ cert = cert_get(GET_ISAKMP_CERTREQ_TYPE(p->p));
+ if (!cert || (len && !cert->certreq_validate(p->p +
+ ISAKMP_CERTREQ_AUTHORITY_OFF, len))) {
+ message_drop(msg, ISAKMP_NOTIFY_CERT_TYPE_UNSUPPORTED, 0, 1,
+ 1);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Validate the delete payload P in message MSG. As a side-effect, create
+ * an exchange if we do not have one already.
+ *
+ * Note: DELETEs are only accepted as part of an INFORMATIONAL exchange.
+ * exchange_validate() makes sure a HASH payload is present. Due to the order
+ * of message validation functions in message_validate_payload[] we can be
+ * sure that the HASH payload has been successfully validated at this point.
+ */
+static int
+message_validate_delete(struct message *msg, struct payload *p)
+{
+ u_int8_t proto = GET_ISAKMP_DELETE_PROTO(p->p);
+ struct doi *doi;
+ struct sa *sa, *isakmp_sa;
+ struct sockaddr *dst, *dst_isa;
+ u_int32_t nspis = GET_ISAKMP_DELETE_NSPIS(p->p);
+ u_int8_t *spis = (u_int8_t *)p->p + ISAKMP_DELETE_SPI_OFF;
+ u_int32_t i;
+ char *addr;
+
+ /* Only accept authenticated DELETEs. */
+ if ((msg->flags & MSG_AUTHENTICATED) == 0) {
+ log_print("message_validate_delete: "
+ "got unauthenticated DELETE");
+ message_free(msg);
+ return -1;
+ }
+
+ doi = doi_lookup(GET_ISAKMP_DELETE_DOI(p->p));
+ if (!doi) {
+ log_print("message_validate_delete: DOI not supported");
+ message_free(msg);
+ return -1;
+ }
+ /* If we don't have an exchange yet, create one. */
+ if (!msg->exchange) {
+ if (zero_test((u_int8_t *) msg->iov[0].iov_base
+ + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN))
+ msg->exchange = exchange_setup_p1(msg, doi->id);
+ else
+ msg->exchange = exchange_setup_p2(msg, doi->id);
+ if (!msg->exchange) {
+ log_print("message_validate_delete: can not create "
+ "exchange");
+ message_free(msg);
+ return -1;
+ }
+ }
+ /* Only accept DELETE as part of an INFORMATIONAL exchange. */
+ if (msg->exchange->type != ISAKMP_EXCH_INFO) {
+ log_print("message_validate_delete: delete in exchange other "
+ "than INFO: %s", constant_name(isakmp_exch_cst,
+ msg->exchange->type));
+ message_free(msg);
+ return -1;
+ }
+ if (proto != ISAKMP_PROTO_ISAKMP && doi->validate_proto(proto)) {
+ log_print("message_validate_delete: protocol not supported");
+ message_free(msg);
+ return -1;
+ }
+ /* Validate the SPIs. */
+ for (i = 0; i < nspis; i++) {
+ /* Get ISAKMP SA protecting this message. */
+ isakmp_sa = msg->isakmp_sa;
+ if (!isakmp_sa) {
+ /* XXX should not happen? */
+ log_print("message_validate_delete: invalid spi (no "
+ "valid ISAKMP SA found)");
+ message_free(msg);
+ return -1;
+ }
+ isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport,
+ &dst_isa);
+
+ /* Get SA to be deleted. */
+ msg->transport->vtbl->get_dst(msg->transport, &dst);
+ if (proto == ISAKMP_PROTO_ISAKMP)
+ sa = sa_lookup_isakmp_sa(dst, spis + i
+ * ISAKMP_HDR_COOKIES_LEN);
+ else
+ sa = ipsec_sa_lookup(dst, ((u_int32_t *) spis)[i],
+ proto);
+ if (!sa) {
+ LOG_DBG((LOG_MESSAGE, 50, "message_validate_delete: "
+ "invalid spi (no valid SA found)"));
+ message_free(msg);
+ return -1;
+ }
+ sa->transport->vtbl->get_dst(sa->transport, &dst);
+
+ /* Destination addresses must match. */
+ if (dst->sa_family != dst_isa->sa_family ||
+ memcmp(sockaddr_addrdata(dst_isa), sockaddr_addrdata(dst),
+ sockaddr_addrlen(dst))) {
+ sockaddr2text(dst_isa, &addr, 0);
+
+ log_print("message_validate_delete: invalid spi "
+ "(illegal delete request from %s)", addr);
+ free(addr);
+ message_free(msg);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Validate the hash payload P in message MSG.
+ * XXX Currently hash payloads are processed by the particular exchanges,
+ * except INFORMATIONAL. This should be actually done here.
+ */
+static int
+message_validate_hash(struct message *msg, struct payload *p)
+{
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa;
+ struct hash *hash;
+ struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH);
+ struct prf *prf;
+ u_int8_t *comp_hash, *rest;
+ u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN];
+ size_t rest_len;
+
+ /* active exchanges other than INFORMATIONAL validates hash payload. */
+ if (msg->exchange && (msg->exchange->type != ISAKMP_EXCH_INFO))
+ return 0;
+
+ if (isakmp_sa == NULL) {
+ log_print("message_validate_hash: invalid hash information");
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
+ 0, 1, 1);
+ return -1;
+ }
+ isa = isakmp_sa->data;
+ hash = hash_get(isa->hash);
+
+ if (hash == NULL) {
+ log_print("message_validate_hash: invalid hash information");
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
+ 0, 1, 1);
+ return -1;
+ }
+ /* If no SKEYID_a, we can not do anything (should not happen). */
+ if (!isa->skeyid_a) {
+ log_print("message_validate_hash: invalid hash information");
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
+ 0, 1, 1);
+ return -1;
+ }
+ /* Allocate the prf and start calculating our HASH(1). */
+ LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: SKEYID_a",
+ isa->skeyid_a, isa->skeyid_len));
+ prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a,
+ isa->skeyid_len);
+ if (!prf) {
+ message_free(msg);
+ return -1;
+ }
+ comp_hash = (u_int8_t *)malloc(hash->hashsize);
+ if (!comp_hash) {
+ log_error("message_validate_hash: malloc (%lu) failed",
+ (unsigned long)hash->hashsize);
+ prf_free(prf);
+ message_free(msg);
+ return -1;
+ }
+ /* This is not an active exchange. */
+ GET_ISAKMP_HDR_MESSAGE_ID(msg->iov[0].iov_base, message_id);
+
+ prf->Init(prf->prfctx);
+ LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: message_id",
+ message_id, ISAKMP_HDR_MESSAGE_ID_LEN));
+ prf->Update(prf->prfctx, message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ rest = hashp->p + GET_ISAKMP_GEN_LENGTH(hashp->p);
+ rest_len = (GET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base) - (rest -
+ (u_int8_t *)msg->iov[0].iov_base));
+ LOG_DBG_BUF((LOG_MISC, 90,
+ "message_validate_hash: payloads after HASH(1)", rest, rest_len));
+ prf->Update(prf->prfctx, rest, rest_len);
+ prf->Final(comp_hash, prf->prfctx);
+ prf_free(prf);
+
+ if (memcmp(hashp->p + ISAKMP_HASH_DATA_OFF, comp_hash,
+ hash->hashsize)) {
+ log_print("message_validate_hash: invalid hash value for %s "
+ "payload", payload_first(msg, ISAKMP_PAYLOAD_DELETE) ?
+ "DELETE" : "NOTIFY");
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
+ 0, 1, 1);
+ free(comp_hash);
+ return -1;
+ }
+ free(comp_hash);
+
+ /* Mark the HASH as handled. */
+ hashp->flags |= PL_MARK;
+
+ /* Mark message as authenticated. */
+ msg->flags |= MSG_AUTHENTICATED;
+
+ return 0;
+}
+
+/* Validate the identification payload P in message MSG. */
+static int
+message_validate_id(struct message *msg, struct payload *p)
+{
+ struct exchange *exchange = msg->exchange;
+ size_t len = GET_ISAKMP_GEN_LENGTH(p->p);
+
+ if (!exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_id: payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+ if (exchange->doi
+ && exchange->doi->validate_id_information(GET_ISAKMP_ID_TYPE(p->p),
+ p->p + ISAKMP_ID_DOI_DATA_OFF, p->p + ISAKMP_ID_DATA_OFF, len -
+ ISAKMP_ID_DATA_OFF, exchange)) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1,
+ 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the key exchange payload P in message MSG. */
+static int
+message_validate_key_exch(struct message *msg, struct payload *p)
+{
+ struct exchange *exchange = msg->exchange;
+ size_t len = GET_ISAKMP_GEN_LENGTH(p->p);
+
+ if (!exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_key_exch: "
+ "payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+ if (exchange->doi && exchange->doi->validate_key_information(p->p +
+ ISAKMP_KE_DATA_OFF, len - ISAKMP_KE_DATA_OFF)) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_KEY_INFORMATION,
+ 0, 1, 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the NAT-D payload P in message MSG. */
+static int
+message_validate_nat_d(struct message *msg, struct payload *p)
+{
+ struct exchange *exchange = msg->exchange;
+
+ if (!exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_nat_d: payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+
+ if (exchange->phase != 1) {
+ log_print("message_validate_nat_d: "
+ "NAT-D payload must be in phase 1");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+
+ /* Mark as handled. */
+ p->flags |= PL_MARK;
+
+ return 0;
+}
+
+/* Validate the NAT-OA payload P in message MSG. */
+static int
+message_validate_nat_oa(struct message *msg, struct payload *p)
+{
+ struct exchange *exchange = msg->exchange;
+
+ if (!exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_nat_d: payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+
+#ifdef notyet /* XXX Probably never, due to patent issues. */
+ /* Mark as handled. */
+ p->flags |= PL_MARK;
+#endif
+
+ return 0;
+}
+
+/* Validate the nonce payload P in message MSG. */
+static int
+message_validate_nonce(struct message *msg, struct payload *p)
+{
+ if (!msg->exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_nonce: payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+ /* Nonces require no specific validation. */
+ return 0;
+}
+
+/*
+ * Validate the notify payload P in message MSG. As a side-effect, create
+ * an exchange if we do not have one already.
+ */
+static int
+message_validate_notify(struct message *msg, struct payload *p)
+{
+ u_int8_t proto = GET_ISAKMP_NOTIFY_PROTO(p->p);
+ u_int16_t type = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p);
+ struct doi *doi;
+
+ doi = doi_lookup(GET_ISAKMP_NOTIFY_DOI(p->p));
+ if (!doi) {
+ log_print("message_validate_notify: DOI not supported");
+ message_free(msg);
+ return -1;
+ }
+ /* If we don't have an exchange yet, create one. */
+ if (!msg->exchange) {
+ if (zero_test((u_int8_t *) msg->iov[0].iov_base +
+ ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN))
+ msg->exchange = exchange_setup_p1(msg, doi->id);
+ else
+ msg->exchange = exchange_setup_p2(msg, doi->id);
+ if (!msg->exchange) {
+ log_print("message_validate_notify: can not create "
+ "exchange");
+ message_free(msg);
+ return -1;
+ }
+ }
+ if (proto != ISAKMP_PROTO_ISAKMP && doi->validate_proto(proto)) {
+ log_print("message_validate_notify: protocol not supported");
+ message_free(msg);
+ return -1;
+ }
+
+ /* Validate the SPI. XXX Just ISAKMP for now. */
+ if (proto == ISAKMP_PROTO_ISAKMP &&
+ GET_ISAKMP_NOTIFY_SPI_SZ(p->p) == ISAKMP_HDR_COOKIES_LEN &&
+ msg->isakmp_sa &&
+ memcmp(p->p + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies,
+ ISAKMP_HDR_COOKIES_LEN) != 0) {
+ log_print("message_validate_notify: bad cookies");
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_SPI, 0, 1, 0);
+ return -1;
+ }
+
+ if (type < ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE
+ || (type >= ISAKMP_NOTIFY_RESERVED_MIN
+ && type < ISAKMP_NOTIFY_PRIVATE_MIN)
+ || (type >= ISAKMP_NOTIFY_STATUS_RESERVED1_MIN
+ && type <= ISAKMP_NOTIFY_STATUS_RESERVED1_MAX)
+ || (type >= ISAKMP_NOTIFY_STATUS_DOI_MIN
+ && type <= ISAKMP_NOTIFY_STATUS_DOI_MAX
+ && doi->validate_notification(type))
+ || type >= ISAKMP_NOTIFY_STATUS_RESERVED2_MIN) {
+ log_print("message_validate_notify: "
+ "message type not supported");
+ message_free(msg);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Validate the proposal payload P in message MSG. */
+static int
+message_validate_proposal(struct message *msg, struct payload *p)
+{
+ u_int8_t proto = GET_ISAKMP_PROP_PROTO(p->p);
+ u_int8_t *sa = p->context->p;
+
+ if (!msg->exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_proposal: "
+ "payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+ if (proto != ISAKMP_PROTO_ISAKMP
+ && msg->exchange->doi->validate_proto(proto)) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_PROTOCOL_ID, 0, 1, 1);
+ return -1;
+ }
+ /* Check that we get monotonically increasing proposal IDs per SA. */
+ if (sa != last_sa)
+ last_sa = sa;
+ else if (GET_ISAKMP_PROP_NO(p->p) < last_prop_no) {
+ message_drop(msg, ISAKMP_NOTIFY_BAD_PROPOSAL_SYNTAX, 0, 1, 1);
+ return -1;
+ }
+ last_prop_no = GET_ISAKMP_PROP_NO(p->p);
+
+ /* XXX Validate the SPI, and other syntactic things. */
+
+ return 0;
+}
+
+/*
+ * Validate the SA payload P in message MSG.
+ * Aside from normal validation, note what DOI is in use for other
+ * validation routines to look at. Also index the proposal payloads
+ * on the fly.
+ * XXX This assumes PAYLOAD_SA is always the first payload
+ * to be validated, which is true for IKE, except for quick mode where
+ * a PAYLOAD_HASH comes first, but in that specific case it does not matter.
+ * XXX Make sure the above comment is relevant, isn't SA always checked
+ * first due to the IANA assigned payload number?
+ */
+static int
+message_validate_sa(struct message *msg, struct payload *p)
+{
+ set payload_set;
+ size_t len;
+ u_int32_t doi_id;
+ struct exchange *exchange = msg->exchange;
+ u_int8_t *pkt = msg->iov[0].iov_base;
+
+ doi_id = GET_ISAKMP_SA_DOI(p->p);
+ if (!doi_lookup(doi_id)) {
+ log_print("message_validate_sa: DOI not supported");
+ message_drop(msg, ISAKMP_NOTIFY_DOI_NOT_SUPPORTED, 0, 1, 1);
+ return -1;
+ }
+ /*
+ * It's time to figure out what SA this message is about. If it is
+ * already set, then we are creating a new phase 1 SA. Otherwise,
+ * lookup the SA using the cookies and the message ID. If we cannot
+ * find it, and the phase 1 SA is ready, setup a phase 2 SA.
+ */
+ if (!exchange) {
+ if (zero_test(pkt + ISAKMP_HDR_RCOOKIE_OFF,
+ ISAKMP_HDR_RCOOKIE_LEN))
+ exchange = exchange_setup_p1(msg, doi_id);
+ else if (msg->isakmp_sa->flags & SA_FLAG_READY)
+ exchange = exchange_setup_p2(msg, doi_id);
+ else {
+ /* XXX What to do here? */
+ message_free(msg);
+ return -1;
+ }
+ if (!exchange) {
+ /* XXX Log? */
+ message_free(msg);
+ return -1;
+ }
+ }
+ msg->exchange = exchange;
+
+ /*
+ * Create a struct sa for each SA payload handed to us unless we are
+ * the initiator where we only will count them.
+ */
+ if (exchange->initiator) {
+ /* XXX Count SA payloads. */
+ } else if (sa_create(exchange, msg->transport)) {
+ /* XXX Remove exchange if we just created it? */
+ message_free(msg);
+ return -1;
+ }
+ if (exchange->phase == 1) {
+ msg->isakmp_sa = TAILQ_FIRST(&exchange->sa_list);
+ if (msg->isakmp_sa)
+ sa_reference(msg->isakmp_sa);
+ }
+ /*
+ * Let the DOI validate the situation, at the same time it tells us
+ * what the length of the situation field is.
+ */
+ if (exchange->doi->validate_situation(p->p + ISAKMP_SA_SIT_OFF, &len,
+ GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_SA_SIT_OFF)) {
+ log_print("message_validate_sa: situation not supported");
+ message_drop(msg, ISAKMP_NOTIFY_SITUATION_NOT_SUPPORTED,
+ 0, 1, 1);
+ return -1;
+ }
+ /*
+ * Reset the fields we base our proposal & transform number checks
+ * on.
+ */
+ last_sa = last_prop = 0;
+ last_prop_no = last_xf_no = 0;
+
+ /* Go through the PROPOSAL payloads. */
+ ZERO(&payload_set);
+ SET(payload_revmap[ISAKMP_PAYLOAD_PROPOSAL], &payload_set);
+ if (message_parse_payloads(msg, p, ISAKMP_PAYLOAD_PROPOSAL,
+ p->p + ISAKMP_SA_SIT_OFF + len, &payload_set,
+ message_parse_proposal) == -1)
+ return -1;
+
+ return 0;
+}
+
+/* Validate the signature payload P in message MSG. */
+static int
+message_validate_sig(struct message *msg, struct payload *p)
+{
+ if (!msg->exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_sig: payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+ /* XXX Not implemented yet. */
+ return 0;
+}
+
+/* Validate the transform payload P in message MSG. */
+static int
+message_validate_transform(struct message *msg, struct payload *p)
+{
+ u_int8_t proto = GET_ISAKMP_PROP_PROTO(p->context->p);
+ u_int8_t *prop = p->context->p;
+
+ if (!msg->exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_transform: "
+ "payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+ if (msg->exchange->doi
+ ->validate_transform_id(proto, GET_ISAKMP_TRANSFORM_ID(p->p))) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_TRANSFORM_ID, 0, 1, 1);
+ return -1;
+ }
+ /* Check that the reserved field is zero. */
+ if (!zero_test(p->p + ISAKMP_TRANSFORM_RESERVED_OFF,
+ ISAKMP_TRANSFORM_RESERVED_LEN)) {
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+ /*
+ * Check that we get monotonically increasing transform numbers per
+ * proposal.
+ */
+ if (prop != last_prop)
+ last_prop = prop;
+ else if (GET_ISAKMP_TRANSFORM_NO(p->p) <= last_xf_no) {
+ message_drop(msg, ISAKMP_NOTIFY_BAD_PROPOSAL_SYNTAX, 0, 1, 1);
+ return -1;
+ }
+ last_xf_no = GET_ISAKMP_TRANSFORM_NO(p->p);
+
+ /* Validate the attributes. */
+ if (attribute_map(p->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ msg->exchange->doi->validate_attribute, msg)) {
+ message_drop(msg, ISAKMP_NOTIFY_ATTRIBUTES_NOT_SUPPORTED,
+ 0, 1, 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the vendor payload P in message MSG. */
+static int
+message_validate_vendor(struct message *msg, struct payload *p)
+{
+ if (!msg->exchange) {
+ /* We should have an exchange at this point. */
+ log_print("message_validate_vendor: payload out of sequence");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ return -1;
+ }
+ /* Vendor IDs are only allowed in phase 1. */
+ if (msg->exchange->phase != 1) {
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1);
+ return -1;
+ }
+#if defined (USE_DPD)
+ dpd_check_vendor_payload(msg, p);
+#endif
+#if defined (USE_NAT_TRAVERSAL)
+ nat_t_check_vendor_payload(msg, p);
+#endif
+ if (!(p->flags & PL_MARK))
+ LOG_DBG((LOG_MESSAGE, 40, "message_validate_vendor: "
+ "vendor ID seen"));
+ return 0;
+}
+
+/*
+ * Add an index-record pointing to the payload at BUF in message MSG
+ * to the PAYLOAD bucket of payloads. This allows us to quickly reference
+ * payloads by type. Also stash the parent payload P link into the new
+ * node so we can go from transforms -> payloads -> SAs.
+ */
+static int
+message_index_payload(struct message *msg, struct payload *p, u_int8_t payload,
+ u_int8_t *buf)
+{
+ struct payload *payload_node;
+
+ /* Put the payload pointer into the right bucket. */
+ payload_node = malloc(sizeof *payload_node);
+ if (!payload_node)
+ return -1;
+ payload_node->p = buf;
+ payload_node->context = p;
+ payload_node->flags = 0;
+ TAILQ_INSERT_TAIL(&msg->payload[payload_map[payload]], payload_node,
+ link);
+ return 0;
+}
+
+/*
+ * Group each payload found in MSG by type for easy reference later.
+ * While doing this, validate the generic parts of the message structure too.
+ * NEXT is the 1st payload's type. This routine will also register the
+ * computed message length (i.e. without padding) in msg->iov[0].iov_len.
+ */
+static int
+message_sort_payloads(struct message *msg, u_int8_t next)
+{
+ set payload_set;
+ int i, sz;
+
+ ZERO(&payload_set);
+ for (i = ISAKMP_PAYLOAD_SA; i < payload_index_max; i++)
+ if (i != ISAKMP_PAYLOAD_PROPOSAL && i !=
+ ISAKMP_PAYLOAD_TRANSFORM)
+ SET(payload_revmap[i], &payload_set);
+ sz = message_parse_payloads(msg, 0, next,
+ (u_int8_t *)msg->iov[0].iov_base + ISAKMP_HDR_SZ, &payload_set,
+ message_index_payload);
+ if (sz == -1)
+ return -1;
+ msg->iov[0].iov_len = ISAKMP_HDR_SZ + sz;
+ SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base, ISAKMP_HDR_SZ + sz);
+ return 0;
+}
+
+/* Run all the generic payload tests that the drafts specify. */
+static int
+message_validate_payloads(struct message *msg)
+{
+ int i;
+ struct payload *p;
+
+ for (i = ISAKMP_PAYLOAD_SA; i < payload_index_max; i++)
+ for (p = payload_first(msg, i); p; p = TAILQ_NEXT(p, link)) {
+ LOG_DBG((LOG_MESSAGE, 60, "message_validate_payloads: "
+ "payload %s at %p of message %p",
+ constant_name(isakmp_payload_cst, i), p->p, msg));
+ field_dump_payload(fields[i - ISAKMP_PAYLOAD_SA],
+ p->p);
+ if (message_validate_payload[i - ISAKMP_PAYLOAD_SA]
+ (msg, p))
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * All incoming messages go through here. We do generic validity checks
+ * and try to find or establish SAs. Last but not least we try to find
+ * the exchange this message, MSG, is part of, and feed it there.
+ */
+int
+message_recv(struct message *msg)
+{
+ u_int8_t *buf = msg->iov[0].iov_base;
+ size_t sz = msg->iov[0].iov_len;
+ u_int8_t exch_type;
+ int setup_isakmp_sa, msgid_is_zero;
+ u_int8_t flags;
+ struct keystate *ks = 0;
+ struct proto tmp_proto;
+ struct sa tmp_sa;
+
+ /* Messages shorter than an ISAKMP header are bad. */
+ if (sz < ISAKMP_HDR_SZ || sz != GET_ISAKMP_HDR_LENGTH(buf)) {
+ log_print("message_recv: bad message length");
+ message_drop(msg, ISAKMP_NOTIFY_UNEQUAL_PAYLOAD_LENGTHS,
+ 0, 1, 1);
+ return -1;
+ }
+#ifdef USE_DEBUG
+ /* Possibly dump a raw hex image of the message to the log channel. */
+ message_dump_raw("message_recv", msg, LOG_MESSAGE);
+#endif
+
+ /*
+ * If the responder cookie is zero, this is a request to setup an
+ * ISAKMP SA. Otherwise the cookies should refer to an existing
+ * ISAKMP SA.
+ *
+ * XXX This is getting ugly, please reread later to see if it can be
+ * made nicer.
+ */
+ setup_isakmp_sa = zero_test(buf + ISAKMP_HDR_RCOOKIE_OFF,
+ ISAKMP_HDR_RCOOKIE_LEN);
+ if (setup_isakmp_sa) {
+ /*
+ * This might be a retransmission of a former ISAKMP SA setup
+ * message. If so, just drop it.
+ * XXX Must we really look in both the SA and exchange pools?
+ */
+ if (exchange_lookup_from_icookie(buf + ISAKMP_HDR_ICOOKIE_OFF)
+ || sa_lookup_from_icookie(buf + ISAKMP_HDR_ICOOKIE_OFF)) {
+ /*
+ * XXX Later we should differentiate between
+ * retransmissions and potential replay attacks.
+ */
+ LOG_DBG((LOG_MESSAGE, 90,
+ "message_recv: dropping setup for existing SA"));
+ message_free(msg);
+ return -1;
+ }
+ } else {
+ msg->isakmp_sa = sa_lookup_by_header(buf, 0);
+ if (msg->isakmp_sa)
+ sa_reference(msg->isakmp_sa);
+
+ /*
+ * If we cannot find an ISAKMP SA out of the cookies, this is
+ * either a responder's first reply, and we need to upgrade
+ * our exchange, or it's just plain invalid cookies.
+ */
+ if (!msg->isakmp_sa) {
+ msg->exchange = exchange_lookup_from_icookie(buf +
+ ISAKMP_HDR_ICOOKIE_OFF);
+ if (msg->exchange && msg->exchange->phase == 1
+ && zero_test(msg->exchange->cookies +
+ ISAKMP_HDR_RCOOKIE_OFF, ISAKMP_HDR_RCOOKIE_LEN))
+ exchange_upgrade_p1(msg);
+ else {
+ log_print("message_recv: invalid cookie(s) "
+ "%08x%08x %08x%08x",
+ decode_32(buf + ISAKMP_HDR_ICOOKIE_OFF),
+ decode_32(buf + ISAKMP_HDR_ICOOKIE_OFF + 4),
+ decode_32(buf + ISAKMP_HDR_RCOOKIE_OFF),
+ decode_32(buf + ISAKMP_HDR_RCOOKIE_OFF + 4));
+ tmp_proto.sa = &tmp_sa;
+ tmp_sa.doi = doi_lookup(ISAKMP_DOI_ISAKMP);
+ tmp_proto.proto = ISAKMP_PROTO_ISAKMP;
+ tmp_proto.spi_sz[1] = ISAKMP_HDR_COOKIES_LEN;
+ tmp_proto.spi[1] =
+ buf + ISAKMP_HDR_COOKIES_OFF;
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_COOKIE,
+ &tmp_proto, 1, 1);
+ return -1;
+ }
+#if 0
+ msg->isakmp_sa = sa_lookup_from_icookie(buf +
+ ISAKMP_HDR_ICOOKIE_OFF);
+ if (msg->isakmp_sa)
+ sa_isakmp_upgrade(msg);
+#endif
+ }
+ msg->exchange = exchange_lookup(buf, 1);
+ }
+
+ if (message_check_duplicate(msg))
+ return -1;
+
+ if (GET_ISAKMP_HDR_NEXT_PAYLOAD(buf) >= ISAKMP_PAYLOAD_RESERVED_MIN) {
+ log_print("message_recv: invalid payload type %d in ISAKMP "
+ "header (check passphrases, if applicable and in Phase 1)",
+ GET_ISAKMP_HDR_NEXT_PAYLOAD(buf));
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1);
+ return -1;
+ }
+ /* Validate that the message is of version 1.0. */
+ if (ISAKMP_VERSION_MAJOR(GET_ISAKMP_HDR_VERSION(buf)) != 1) {
+ log_print("message_recv: invalid version major %d",
+ ISAKMP_VERSION_MAJOR(GET_ISAKMP_HDR_VERSION(buf)));
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_MAJOR_VERSION, 0, 1,
+ 1);
+ return -1;
+ }
+ if (ISAKMP_VERSION_MINOR(GET_ISAKMP_HDR_VERSION(buf)) != 0) {
+ log_print("message_recv: invalid version minor %d",
+ ISAKMP_VERSION_MINOR(GET_ISAKMP_HDR_VERSION(buf)));
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_MINOR_VERSION, 0, 1,
+ 1);
+ return -1;
+ }
+ /*
+ * Validate the exchange type. If it's a DOI-specified exchange wait
+ * until after all payloads have been seen for the validation as the
+ * SA payload might not yet have been parsed, thus the DOI might be
+ * unknown.
+ */
+ exch_type = GET_ISAKMP_HDR_EXCH_TYPE(buf);
+ if (exch_type == ISAKMP_EXCH_NONE
+ || (exch_type >= ISAKMP_EXCH_FUTURE_MIN &&
+ exch_type <= ISAKMP_EXCH_FUTURE_MAX)
+ || (setup_isakmp_sa && exch_type >= ISAKMP_EXCH_DOI_MIN)) {
+ log_print("message_recv: invalid exchange type %s",
+ constant_name(isakmp_exch_cst, exch_type));
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_EXCHANGE_TYPE, 0, 1,
+ 1);
+ return -1;
+ }
+ /*
+ * Check for unrecognized flags, or the encryption flag when we don't
+ * have an ISAKMP SA to decrypt with.
+ */
+ flags = GET_ISAKMP_HDR_FLAGS(buf);
+ if (flags & ~(ISAKMP_FLAGS_ENC | ISAKMP_FLAGS_COMMIT |
+ ISAKMP_FLAGS_AUTH_ONLY)) {
+ log_print("message_recv: invalid flags 0x%x",
+ GET_ISAKMP_HDR_FLAGS(buf));
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 1, 1);
+ return -1;
+ }
+ /*
+ * If we are about to setup an ISAKMP SA, the message ID must be
+ * zero.
+ */
+ msgid_is_zero = zero_test(buf + ISAKMP_HDR_MESSAGE_ID_OFF,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ if (setup_isakmp_sa && !msgid_is_zero) {
+ log_print("message_recv: invalid message id");
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_MESSAGE_ID, 0, 1, 1);
+ return -1;
+ }
+ if (!setup_isakmp_sa && msgid_is_zero) {
+ /*
+ * XXX Very likely redundant, look at the else clause of the
+ * if (setup_isakmp_sa) statement above.
+ */
+ msg->exchange = exchange_lookup(buf, 0);
+ if (!msg->exchange) {
+ log_print("message_recv: phase 1 message after "
+ "ISAKMP SA is ready");
+ message_free(msg);
+ return -1;
+ } else if (msg->exchange->last_sent) {
+ LOG_DBG((LOG_MESSAGE, 80, "message_recv: resending "
+ "last message from phase 1"));
+ message_send(msg->exchange->last_sent);
+ }
+ }
+ if (flags & ISAKMP_FLAGS_ENC) {
+ if (!msg->isakmp_sa) {
+ LOG_DBG((LOG_MISC, 10, "message_recv: no isakmp_sa "
+ "for encrypted message"));
+ message_free(msg);
+ return -1;
+ }
+ /* Decrypt rest of message using a DOI-specified IV. */
+ ks = msg->isakmp_sa->doi->get_keystate(msg);
+ if (!ks) {
+ message_free(msg);
+ return -1;
+ }
+ msg->orig = malloc(sz);
+ if (!msg->orig) {
+ message_free(msg);
+ free(ks);
+ return -1;
+ }
+ memcpy(msg->orig, buf, sz);
+ crypto_decrypt(ks, buf + ISAKMP_HDR_SZ, sz - ISAKMP_HDR_SZ);
+ } else
+ msg->orig = buf;
+ msg->orig_sz = sz;
+
+ /* IKE packet capture */
+ message_packet_log(msg);
+
+ /*
+ * Check the overall payload structure at the same time as indexing
+ * them by type.
+ */
+ if (GET_ISAKMP_HDR_NEXT_PAYLOAD(buf) != ISAKMP_PAYLOAD_NONE
+ && message_sort_payloads(msg, GET_ISAKMP_HDR_NEXT_PAYLOAD(buf))) {
+ if (ks)
+ free(ks);
+ return -1;
+ }
+ /*
+ * Run generic payload tests now. If anything fails these checks, the
+ * message needs either to be retained for later duplicate checks or
+ * freed entirely.
+ * XXX Should SAs and even transports be cleaned up then too?
+ */
+ if (message_validate_payloads(msg)) {
+ if (ks)
+ free(ks);
+ return -1;
+ }
+ /*
+ * If we have not found an exchange by now something is definitely
+ * wrong.
+ */
+ if (!msg->exchange) {
+ log_print("message_recv: no exchange");
+ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1);
+ if (ks)
+ free(ks);
+ return -1;
+ }
+ /*
+ * Now we can validate DOI-specific exchange types. If we have no SA
+ * DOI-specific exchange types are definitely wrong.
+ */
+ if (exch_type >= ISAKMP_EXCH_DOI_MIN
+ && exch_type <= ISAKMP_EXCH_DOI_MAX
+ && msg->exchange->doi->validate_exchange(exch_type)) {
+ log_print("message_recv: invalid DOI exchange type %d",
+ exch_type);
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_EXCHANGE_TYPE, 0, 1,
+ 1);
+ if (ks)
+ free(ks);
+ return -1;
+ }
+ /* Make sure the IV we used gets saved in the proper SA. */
+ if (ks) {
+ if (!msg->exchange->keystate) {
+ msg->exchange->keystate = ks;
+ msg->exchange->crypto = ks->xf;
+ } else
+ free(ks);
+ }
+ /* Handle the flags. */
+ if (flags & ISAKMP_FLAGS_ENC)
+ msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+ if ((msg->exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0
+ && (flags & ISAKMP_FLAGS_COMMIT))
+ msg->exchange->flags |= EXCHANGE_FLAG_HE_COMMITTED;
+
+ /*
+ * Except for the 3rd Aggressive Mode message, require encryption
+ * as soon as we have the keystate for it.
+ */
+ if ((flags & ISAKMP_FLAGS_ENC) == 0 &&
+ (msg->exchange->phase == 2 ||
+ (msg->exchange->keystate &&
+ msg->exchange->type != ISAKMP_EXCH_AGGRESSIVE))) {
+ log_print("message_recv: cleartext phase %d message",
+ msg->exchange->phase);
+ message_drop(msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 1, 1);
+ return -1;
+ }
+
+ /* OK let the exchange logic do the rest. */
+ exchange_run(msg);
+
+ return 0;
+}
+
+void
+message_send_expire(struct message *msg)
+{
+ msg->retrans = 0;
+
+ message_send(msg);
+}
+
+/* Queue up message MSG for transmittal. */
+void
+message_send(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct message *m;
+ struct msg_head *q;
+
+ /* Remove retransmissions on this message */
+ if (msg->retrans) {
+ timer_remove_event(msg->retrans);
+ msg->retrans = 0;
+ }
+ /* IKE packet capture */
+ message_packet_log(msg);
+
+ /*
+ * If the ISAKMP SA has set up encryption, encrypt the message.
+ * However, in a retransmit, it is already encrypted.
+ */
+ if ((msg->flags & MSG_ENCRYPTED) == 0
+ && exchange->flags & EXCHANGE_FLAG_ENCRYPT) {
+ if (!exchange->keystate) {
+ exchange->keystate = exchange->doi->get_keystate(msg);
+ if (!exchange->keystate)
+ return;
+ exchange->crypto = exchange->keystate->xf;
+ exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+ }
+ if (message_encrypt(msg)) {
+ /* XXX Log. */
+ return;
+ }
+ }
+ /* Keep the COMMIT bit on. */
+ if (exchange->flags & EXCHANGE_FLAG_COMMITTED)
+ SET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base,
+ GET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base)
+ | ISAKMP_FLAGS_COMMIT);
+
+#ifdef USE_DEBUG
+ message_dump_raw("message_send", msg, LOG_MESSAGE);
+#endif
+ msg->flags |= MSG_IN_TRANSIT;
+ exchange->in_transit = msg;
+
+ /*
+ * If we get a retransmission of a message before our response
+ * has left the queue, don't queue it again, as it will result
+ * in a circular list.
+ */
+ q = msg->transport->vtbl->get_queue(msg);
+ for (m = TAILQ_FIRST(q); m; m = TAILQ_NEXT(m, link))
+ if (m == msg) {
+ LOG_DBG((LOG_MESSAGE, 60,
+ "message_send: msg %p already on sendq %p", m, q));
+ return;
+ }
+ TAILQ_INSERT_TAIL(q, msg, link);
+}
+
+/*
+ * Setup the ISAKMP message header for message MSG. EXCHANGE is the exchange
+ * type, FLAGS are the ISAKMP header flags and MSG_ID is message ID
+ * identifying the exchange.
+ */
+void
+message_setup_header(struct message *msg, u_int8_t exchange, u_int8_t flags,
+ u_int8_t *msg_id)
+{
+ u_int8_t *buf = msg->iov[0].iov_base;
+
+ SET_ISAKMP_HDR_ICOOKIE(buf, msg->exchange->cookies);
+ SET_ISAKMP_HDR_RCOOKIE(buf, msg->exchange->cookies +
+ ISAKMP_HDR_ICOOKIE_LEN);
+ SET_ISAKMP_HDR_NEXT_PAYLOAD(buf, ISAKMP_PAYLOAD_NONE);
+ SET_ISAKMP_HDR_VERSION(buf, ISAKMP_VERSION_MAKE(1, 0));
+ SET_ISAKMP_HDR_EXCH_TYPE(buf, exchange);
+ SET_ISAKMP_HDR_FLAGS(buf, flags);
+ SET_ISAKMP_HDR_MESSAGE_ID(buf, msg_id);
+ SET_ISAKMP_HDR_LENGTH(buf, msg->iov[0].iov_len);
+}
+
+/*
+ * Add the payload of type PAYLOAD in BUF sized SZ to the MSG message.
+ * The caller thereby is released from the responsibility of freeing BUF,
+ * unless we return a failure of course. If LINK is set the former
+ * payload's "next payload" field to PAYLOAD.
+ *
+ * XXX We might want to resize the iov array several slots at a time.
+ */
+int
+message_add_payload(struct message *msg, u_int8_t payload, u_int8_t *buf,
+ size_t sz, int link)
+{
+ struct iovec *new_iov;
+ struct payload *payload_node;
+
+ payload_node = calloc(1, sizeof *payload_node);
+ if (!payload_node) {
+ log_error("message_add_payload: calloc (1, %lu) failed",
+ (unsigned long)sizeof *payload_node);
+ return -1;
+ }
+ new_iov = (struct iovec *) realloc(msg->iov, (msg->iovlen + 1) *
+ sizeof *msg->iov);
+ if (!new_iov) {
+ log_error("message_add_payload: realloc (%p, %lu) failed",
+ msg->iov, (msg->iovlen + 1) *
+ (unsigned long)sizeof *msg->iov);
+ free(payload_node);
+ return -1;
+ }
+ msg->iov = new_iov;
+ new_iov[msg->iovlen].iov_base = buf;
+ new_iov[msg->iovlen].iov_len = sz;
+ msg->iovlen++;
+ if (link)
+ *msg->nextp = payload;
+ msg->nextp = buf + ISAKMP_GEN_NEXT_PAYLOAD_OFF;
+ *msg->nextp = ISAKMP_PAYLOAD_NONE;
+ SET_ISAKMP_GEN_RESERVED(buf, 0);
+ SET_ISAKMP_GEN_LENGTH(buf, sz);
+ SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base,
+ GET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base) + sz);
+
+ /*
+ * For the sake of exchange_validate we index the payloads even in
+ * outgoing messages, however context and flags are uninteresting in
+ * this situation.
+ */
+ payload_node->p = buf;
+ TAILQ_INSERT_TAIL(&msg->payload[payload_map[payload]], payload_node,
+ link);
+ return 0;
+}
+
+/* XXX Move up when ready. */
+struct info_args {
+ char discr;
+ u_int32_t doi;
+ u_int8_t proto;
+ u_int16_t spi_sz;
+ union {
+ struct {
+ u_int16_t msg_type;
+ u_int8_t *spi;
+ } n;
+ struct {
+ u_int16_t nspis;
+ u_int8_t *spis;
+ } d;
+#if defined (USE_DPD)
+ struct {
+ u_int16_t msg_type;
+ u_int8_t *spi;
+ u_int32_t seq;
+ } dpd;
+#endif
+ } u;
+};
+
+/*
+ * As a reaction to the incoming message MSG create an informational exchange
+ * protected by ISAKMP_SA and send a notify payload of type NOTIFY, with
+ * fields initialized from SA. INCOMING is true if the SPI field should be
+ * filled with the incoming SPI and false if it is to be filled with the
+ * outgoing one.
+ *
+ * XXX Should we handle sending multiple notify payloads? The draft allows
+ * it, but do we need it? Furthermore, should we not return a success
+ * status value?
+ */
+void
+message_send_notification(struct message *msg, struct sa *isakmp_sa,
+ u_int16_t notify, struct proto *proto, int incoming)
+{
+ struct info_args args;
+ struct sa *doi_sa = proto ? proto->sa : isakmp_sa;
+
+ args.discr = 'N';
+ args.doi = doi_sa ? doi_sa->doi->id : ISAKMP_DOI_ISAKMP;
+ args.proto = proto ? proto->proto : ISAKMP_PROTO_ISAKMP;
+ args.spi_sz = proto ? proto->spi_sz[incoming] : 0;
+ args.u.n.msg_type = notify;
+ args.u.n.spi = proto ? proto->spi[incoming] : 0;
+ if (isakmp_sa && (isakmp_sa->flags & SA_FLAG_READY))
+ exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args,
+ 0, 0);
+ else
+ exchange_establish_p1(msg->transport, ISAKMP_EXCH_INFO,
+ msg->exchange ? msg->exchange->doi->id : ISAKMP_DOI_ISAKMP,
+ 0, &args, 0, 0);
+}
+
+/* Send a DELETE inside an informational exchange for each protocol in SA. */
+void
+message_send_delete(struct sa *sa)
+{
+ struct info_args args;
+ struct proto *proto;
+ struct sa *isakmp_sa;
+ struct sockaddr *dst;
+
+ sa->transport->vtbl->get_dst(sa->transport, &dst);
+ isakmp_sa = sa_isakmp_lookup_by_peer(dst, sysdep_sa_len(dst));
+ if (!isakmp_sa) {
+ /*
+ * XXX We ought to setup an ISAKMP SA with our peer here and
+ * send the DELETE over that one.
+ */
+ return;
+ }
+ args.discr = 'D';
+ args.doi = sa->doi->id;
+ args.u.d.nspis = 1;
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link)) {
+ args.proto = proto->proto;
+ args.spi_sz = proto->spi_sz[1];
+ args.u.d.spis = proto->spi[1];
+ exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args,
+ 0, 0);
+ }
+}
+
+#if defined (USE_DPD)
+void
+message_send_dpd_notify(struct sa* isakmp_sa, u_int16_t notify, u_int32_t seq)
+{
+ struct info_args args;
+
+ args.discr = 'P';
+ args.doi = IPSEC_DOI_IPSEC;
+ args.proto = ISAKMP_PROTO_ISAKMP;
+ args.spi_sz = ISAKMP_HDR_COOKIES_LEN;
+ args.u.dpd.msg_type = notify;
+ args.u.dpd.spi = isakmp_sa->cookies;
+ args.u.dpd.seq = htonl(seq);
+
+ exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, 0, 0);
+}
+#endif
+
+/* Build the informational message into MSG. */
+int
+message_send_info(struct message *msg)
+{
+ u_int8_t *buf;
+ size_t sz = 0;
+ struct info_args *args = msg->extra;
+ u_int8_t payload;
+
+ /* Let the DOI get the first hand on the message. */
+ if (msg->exchange->doi->informational_pre_hook)
+ if (msg->exchange->doi->informational_pre_hook(msg))
+ return -1;
+
+ switch (args->discr) {
+#if defined (USE_DPD)
+ case 'P':
+ sz = sizeof args->u.dpd.seq;
+ /* FALLTHROUGH */
+#endif
+ case 'N':
+ sz += ISAKMP_NOTIFY_SPI_OFF + args->spi_sz;
+ break;
+ case 'D':
+ default: /* Silence gcc */
+ sz = ISAKMP_DELETE_SPI_OFF + args->u.d.nspis * args->spi_sz;
+ break;
+ }
+
+ buf = calloc(1, sz);
+ if (!buf) {
+ log_error("message_send_info: calloc (1, %lu) failed",
+ (unsigned long)sz);
+ message_free(msg);
+ return -1;
+ }
+ switch (args->discr) {
+#if defined (USE_DPD)
+ case 'P':
+ memcpy(buf + ISAKMP_NOTIFY_SPI_OFF + args->spi_sz,
+ &args->u.dpd.seq, sizeof args->u.dpd.seq);
+ /* FALLTHROUGH */
+#endif
+ case 'N':
+ /* Build the NOTIFY payload. */
+ payload = ISAKMP_PAYLOAD_NOTIFY;
+ SET_ISAKMP_NOTIFY_DOI(buf, args->doi);
+ SET_ISAKMP_NOTIFY_PROTO(buf, args->proto);
+ SET_ISAKMP_NOTIFY_SPI_SZ(buf, args->spi_sz);
+ SET_ISAKMP_NOTIFY_MSG_TYPE(buf, args->u.n.msg_type);
+ memcpy(buf + ISAKMP_NOTIFY_SPI_OFF, args->u.n.spi,
+ args->spi_sz);
+ break;
+
+ case 'D':
+ default: /* Silence GCC. */
+ /* Build the DELETE payload. */
+ payload = ISAKMP_PAYLOAD_DELETE;
+ SET_ISAKMP_DELETE_DOI(buf, args->doi);
+ SET_ISAKMP_DELETE_PROTO(buf, args->proto);
+ SET_ISAKMP_DELETE_SPI_SZ(buf, args->spi_sz);
+ SET_ISAKMP_DELETE_NSPIS(buf, args->u.d.nspis);
+ memcpy(buf + ISAKMP_DELETE_SPI_OFF, args->u.d.spis,
+ args->u.d.nspis * args->spi_sz);
+ msg->flags |= MSG_PRIORITIZED;
+ break;
+ }
+
+ if (message_add_payload(msg, payload, buf, sz, 1)) {
+ free(buf);
+ message_free(msg);
+ return -1;
+ }
+ /* Let the DOI get the last hand on the message. */
+ if (msg->exchange->doi->informational_post_hook)
+ if (msg->exchange->doi->informational_post_hook(msg)) {
+ message_free(msg);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Drop the MSG message due to reason given in NOTIFY. If NOTIFY is set
+ * send out a notification to the originator. Fill this notification with
+ * values from PROTO. INCOMING decides which SPI to include. If CLEAN is
+ * set, free the message when ready with it.
+ */
+void
+message_drop(struct message *msg, int notify, struct proto *proto,
+ int incoming, int clean)
+{
+ struct transport *t = msg->transport;
+ struct sockaddr *dst;
+ char *address;
+ short port = 0;
+
+ t->vtbl->get_dst(t, &dst);
+ if (sockaddr2text(dst, &address, 0)) {
+ log_error("message_drop: sockaddr2text () failed");
+ address = 0;
+ }
+ switch (dst->sa_family) {
+ case AF_INET:
+ port = ((struct sockaddr_in *)dst)->sin_port;
+ break;
+ case AF_INET6:
+ port = ((struct sockaddr_in6 *)dst)->sin6_port;
+ break;
+ default:
+ log_print("message_drop: unknown protocol family %d",
+ dst->sa_family);
+ }
+
+ log_print("dropped message from %s port %d due to notification type "
+ "%s", address ? address : "<unknown>", htons(port),
+ constant_name(isakmp_notify_cst, notify));
+
+ if (address)
+ free(address);
+
+ /* If specified, return a notification. */
+ if (notify)
+ message_send_notification(msg, msg->isakmp_sa, notify, proto,
+ incoming);
+ if (clean)
+ message_free(msg);
+}
+
+/*
+ * If the user demands debug printouts, printout MSG with as much detail
+ * as we can without resorting to per-payload handling.
+ */
+void
+message_dump_raw(char *header, struct message *msg, int class)
+{
+ u_int32_t i, j, k = 0;
+ char buf[80], *p = buf;
+
+ LOG_DBG((class, 70, "%s: message %p", header, msg));
+ field_dump_payload(isakmp_hdr_fld, msg->iov[0].iov_base);
+ for (i = 0; i < msg->iovlen; i++)
+ for (j = 0; j < msg->iov[i].iov_len; j++) {
+ snprintf(p, sizeof buf - (int) (p - buf), "%02x",
+ ((u_int8_t *) msg->iov[i].iov_base)[j]);
+ p += 2;
+ if (++k % 32 == 0) {
+ *p = '\0';
+ LOG_DBG((class, 70, "%s: %s", header, buf));
+ p = buf;
+ } else if (k % 4 == 0)
+ *p++ = ' ';
+ }
+ *p = '\0';
+ if (p != buf)
+ LOG_DBG((class, 70, "%s: %s", header, buf));
+}
+
+static void
+message_packet_log(struct message *msg)
+{
+#if defined (USE_DEBUG)
+ struct sockaddr *src, *dst;
+ struct transport *t = msg->transport;
+
+ /* Don't log retransmissions. Redundant for incoming packets... */
+ if (msg->xmits > 0)
+ return;
+
+#if defined (USE_NAT_TRAVERSAL)
+ if (msg->exchange && msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE)
+ t = ((struct virtual_transport *)msg->transport)->encap;
+#endif
+
+ /* Figure out direction. */
+ if (msg->exchange &&
+ msg->exchange->initiator ^ (msg->exchange->step % 2)) {
+ t->vtbl->get_src(t, &src);
+ t->vtbl->get_dst(t, &dst);
+ } else {
+ t->vtbl->get_src(t, &dst);
+ t->vtbl->get_dst(t, &src);
+ }
+
+ log_packet_iov(src, dst, msg->iov, msg->iovlen);
+#endif /* USE_DEBUG */
+}
+
+/*
+ * Encrypt an outgoing message MSG. As outgoing messages are represented
+ * with an iovec with one segment per payload, we need to coalesce them
+ * into just une buffer containing all payloads and some padding before
+ * we encrypt.
+ */
+static int
+message_encrypt(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ size_t i, sz = 0;
+ u_int8_t *buf;
+
+ /* If no payloads, nothing to do. */
+ if (msg->iovlen == 1)
+ return 0;
+
+ /*
+ * For encryption we need to put all payloads together in a single
+ * buffer. This buffer should be padded to the current crypto
+ * transform's blocksize.
+ */
+ for (i = 1; i < msg->iovlen; i++)
+ sz += msg->iov[i].iov_len;
+ sz = ((sz + exchange->crypto->blocksize - 1) /
+ exchange->crypto->blocksize) * exchange->crypto->blocksize;
+ buf = realloc(msg->iov[1].iov_base, sz);
+ if (!buf) {
+ log_error("message_encrypt: realloc (%p, %lu) failed",
+ msg->iov[1].iov_base, (unsigned long) sz);
+ return -1;
+ }
+ msg->iov[1].iov_base = buf;
+ for (i = 2; i < msg->iovlen; i++) {
+ memcpy(buf + msg->iov[1].iov_len, msg->iov[i].iov_base,
+ msg->iov[i].iov_len);
+ msg->iov[1].iov_len += msg->iov[i].iov_len;
+ free(msg->iov[i].iov_base);
+ }
+
+ /* Pad with zeroes. */
+ memset(buf + msg->iov[1].iov_len, '\0', sz - msg->iov[1].iov_len);
+ msg->iov[1].iov_len = sz;
+ msg->iovlen = 2;
+
+ SET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base,
+ GET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base) | ISAKMP_FLAGS_ENC);
+ SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base, ISAKMP_HDR_SZ + sz);
+ crypto_encrypt(exchange->keystate, buf, msg->iov[1].iov_len);
+ msg->flags |= MSG_ENCRYPTED;
+
+ /* Update the IV so we can decrypt the next incoming message. */
+ crypto_update_iv(exchange->keystate);
+
+ return 0;
+}
+
+/*
+ * Check whether the message MSG is a duplicate of the last one negotiating
+ * this specific SA.
+ */
+static int
+message_check_duplicate(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ size_t sz = msg->iov[0].iov_len;
+ u_int8_t *pkt = msg->iov[0].iov_base;
+
+ /* If no SA has been found, we cannot test, thus it's good. */
+ if (!exchange)
+ return 0;
+
+ LOG_DBG((LOG_MESSAGE, 90, "message_check_duplicate: last_received %p",
+ exchange->last_received));
+ if (exchange->last_received) {
+ LOG_DBG_BUF((LOG_MESSAGE, 95,
+ "message_check_duplicate: last_received",
+ exchange->last_received->orig,
+ exchange->last_received->orig_sz));
+ /* Is it a duplicate, lose the new one. */
+ if (sz == exchange->last_received->orig_sz
+ && memcmp(pkt, exchange->last_received->orig, sz) == 0) {
+ LOG_DBG((LOG_MESSAGE, 80,
+ "message_check_duplicate: dropping dup"));
+
+ /*
+ * Retransmit if the previos sent message was the last
+ * of an exchange, otherwise just wait for the
+ * ordinary retransmission.
+ */
+ if (exchange->last_sent && (exchange->last_sent->flags
+ & MSG_LAST))
+ message_send(exchange->last_sent);
+ message_free(msg);
+ return -1;
+ }
+ }
+ /*
+ * As this new message is an indication that state is moving forward
+ * at the peer, remove the retransmit timer on our last message.
+ */
+ if (exchange->last_sent) {
+ if (exchange->last_sent == exchange->in_transit) {
+ struct message *m = exchange->in_transit;
+ TAILQ_REMOVE(m->transport->vtbl->get_queue(m), m,
+ link);
+ exchange->in_transit = 0;
+ }
+ message_free(exchange->last_sent);
+ exchange->last_sent = 0;
+ }
+ return 0;
+}
+
+/* Helper to message_negotiate_sa. */
+static INLINE struct payload *
+step_transform(struct payload *tp, struct payload **propp,
+ struct payload **sap)
+{
+ tp = TAILQ_NEXT(tp, link);
+ if (tp) {
+ *propp = tp->context;
+ *sap = (*propp)->context;
+ }
+ return tp;
+}
+
+/*
+ * Pick out the first transforms out of MSG (which should contain at least one
+ * SA payload) we accept as a full protection suite.
+ */
+int
+message_negotiate_sa(struct message *msg, int (*validate)(struct exchange *,
+ struct sa *, struct sa *))
+{
+ struct payload *tp, *propp, *sap, *next_tp = 0, *next_propp, *next_sap;
+ struct payload *saved_tp = 0, *saved_propp = 0, *saved_sap = 0;
+ struct sa *sa;
+ struct proto *proto;
+ int suite_ok_so_far = 0;
+ struct exchange *exchange = msg->exchange;
+
+ /*
+ * This algorithm is a weird bottom-up thing... mostly due to the
+ * payload links pointing upwards.
+ *
+ * The algorithm goes something like this:
+ * Foreach transform
+ * If transform is compatible
+ * Remember that this protocol can work
+ * Skip to last transform of this protocol
+ * If next transform belongs to a new protocol inside the same suite
+ * If no transform was found for the current protocol
+ * Forget all earlier transforms for protocols in this suite
+ * Skip to last transform of this suite
+ * If next transform belongs to a new suite
+ * If the current protocol had an OK transform
+ * Skip to the last transform of this SA
+ * If the next transform belongs to a new SA
+ * If no transforms have been chosen
+ * Issue a NO_PROPOSAL_CHOSEN notification
+ */
+
+ sa = TAILQ_FIRST(&exchange->sa_list);
+ for (tp = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM); tp;
+ tp = next_tp) {
+ propp = tp->context;
+ sap = propp->context;
+ sap->flags |= PL_MARK;
+ next_tp = step_transform(tp, &next_propp, &next_sap);
+
+ /* For each transform, see if it is compatible. */
+ if (!attribute_map(tp->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH(tp->p) -
+ ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ exchange->doi->is_attribute_incompatible, msg)) {
+ LOG_DBG((LOG_NEGOTIATION, 30, "message_negotiate_sa: "
+ "transform %d proto %d proposal %d ok",
+ GET_ISAKMP_TRANSFORM_NO(tp->p),
+ GET_ISAKMP_PROP_PROTO(propp->p),
+ GET_ISAKMP_PROP_NO(propp->p)));
+ if (sa_add_transform(sa, tp, exchange->initiator,
+ &proto))
+ goto cleanup;
+ suite_ok_so_far = 1;
+
+ saved_tp = next_tp;
+ saved_propp = next_propp;
+ saved_sap = next_sap;
+ /* Skip to last transform of this protocol proposal. */
+ while ((next_tp = step_transform(tp, &next_propp,
+ &next_sap)) && next_propp == propp)
+ tp = next_tp;
+ }
+retry_transform:
+ /*
+ * Figure out if we will be looking at a new protocol proposal
+ * inside the current protection suite.
+ */
+ if (next_tp && propp != next_propp && sap == next_sap
+ && (GET_ISAKMP_PROP_NO(propp->p)
+ == GET_ISAKMP_PROP_NO(next_propp->p))) {
+ if (!suite_ok_so_far) {
+ LOG_DBG((LOG_NEGOTIATION, 30,
+ "message_negotiate_sa: proto %d proposal "
+ "%d failed",
+ GET_ISAKMP_PROP_PROTO(propp->p),
+ GET_ISAKMP_PROP_NO(propp->p)));
+ /*
+ * Remove potentially succeeded choices from
+ * the SA.
+ */
+ while (TAILQ_FIRST(&sa->protos))
+ TAILQ_REMOVE(&sa->protos,
+ TAILQ_FIRST(&sa->protos), link);
+
+ /*
+ * Skip to the last transform of this
+ * protection suite.
+ */
+ while ((next_tp = step_transform(tp,
+ &next_propp, &next_sap))
+ && (GET_ISAKMP_PROP_NO(next_propp->p)
+ == GET_ISAKMP_PROP_NO(propp->p))
+ && next_sap == sap)
+ tp = next_tp;
+ }
+ suite_ok_so_far = 0;
+ }
+ /*
+ * Figure out if we will be looking at a new protection
+ * suite.
+ */
+ if (!next_tp
+ || (propp != next_propp && (GET_ISAKMP_PROP_NO(propp->p)
+ != GET_ISAKMP_PROP_NO(next_propp->p)))
+ || sap != next_sap) {
+ /*
+ * Check if the suite we just considered was OK, if so
+ * we check it against the accepted ones.
+ */
+ if (suite_ok_so_far) {
+ if (!validate || validate(exchange, sa,
+ msg->isakmp_sa)) {
+ LOG_DBG((LOG_NEGOTIATION, 30,
+ "message_negotiate_sa: proposal "
+ "%d succeeded",
+ GET_ISAKMP_PROP_NO(propp->p)));
+
+ /*
+ * Skip to the last transform of this
+ * SA.
+ */
+ while ((next_tp = step_transform(tp,
+ &next_propp, &next_sap))
+ && next_sap == sap)
+ tp = next_tp;
+ } else {
+ /* Backtrack. */
+ LOG_DBG((LOG_NEGOTIATION, 30,
+ "message_negotiate_sa: proposal "
+ "%d failed",
+ GET_ISAKMP_PROP_NO(propp->p)));
+ next_tp = saved_tp;
+ next_propp = saved_propp;
+ next_sap = saved_sap;
+ suite_ok_so_far = 0;
+
+ /*
+ * Remove potentially succeeded
+ * choices from the SA.
+ */
+ while (TAILQ_FIRST(&sa->protos))
+ TAILQ_REMOVE(&sa->protos,
+ TAILQ_FIRST(&sa->protos),
+ link);
+ goto retry_transform;
+ }
+ }
+ }
+ /* Have we walked all the proposals of an SA? */
+ if (!next_tp || sap != next_sap) {
+ if (!suite_ok_so_far) {
+ /*
+ * XXX We cannot possibly call this a drop...
+ * seeing we just turn down one of the offers,
+ * can we? I suggest renaming message_drop to
+ * something else.
+ */
+ log_print("message_negotiate_sa: no "
+ "compatible proposal found");
+ message_drop(msg,
+ ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);
+ }
+ sa = TAILQ_NEXT(sa, next);
+ }
+ }
+ return 0;
+
+cleanup:
+ /*
+ * Remove potentially succeeded choices from the SA.
+ * XXX Do we leak struct protos and related data here?
+ */
+ while (TAILQ_FIRST(&sa->protos))
+ TAILQ_REMOVE(&sa->protos, TAILQ_FIRST(&sa->protos), link);
+ return -1;
+}
+
+/*
+ * Add SA, proposal and transform payload(s) to MSG out of information
+ * found in the exchange MSG is part of..
+ */
+int
+message_add_sa_payload(struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ u_int8_t *sa_buf, *saved_nextp_sa, *saved_nextp_prop;
+ size_t sa_len, extra_sa_len;
+ int i, nprotos = 0;
+ struct proto *proto;
+ u_int8_t **transforms = 0, **proposals = 0;
+ size_t *transform_lens = 0, *proposal_lens = 0;
+ struct sa *sa;
+ struct doi *doi = exchange->doi;
+ u_int8_t *spi = 0;
+ size_t spi_sz;
+
+ /*
+ * Generate SA payloads.
+ */
+ for (sa = TAILQ_FIRST(&exchange->sa_list); sa;
+ sa = TAILQ_NEXT(sa, next)) {
+ /* Setup a SA payload. */
+ sa_len = ISAKMP_SA_SIT_OFF + doi->situation_size();
+ extra_sa_len = 0;
+ sa_buf = malloc(sa_len);
+ if (!sa_buf) {
+ log_error("message_add_sa_payload: "
+ "malloc (%lu) failed", (unsigned long)sa_len);
+ goto cleanup;
+ }
+ SET_ISAKMP_SA_DOI(sa_buf, doi->id);
+ doi->setup_situation(sa_buf);
+
+ /* Count transforms. */
+ nprotos = 0;
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link))
+ nprotos++;
+
+ /*
+ * Allocate transient transform and proposal payload/size
+ * vectors.
+ */
+ transforms = calloc(nprotos, sizeof *transforms);
+ if (!transforms) {
+ log_error("message_add_sa_payload: calloc (%d, %lu) "
+ "failed", nprotos,
+ (unsigned long)sizeof *transforms);
+ goto cleanup;
+ }
+ transform_lens = calloc(nprotos, sizeof *transform_lens);
+ if (!transform_lens) {
+ log_error("message_add_sa_payload: calloc (%d, %lu) "
+ "failed", nprotos,
+ (unsigned long) sizeof *transform_lens);
+ goto cleanup;
+ }
+ proposals = calloc(nprotos, sizeof *proposals);
+ if (!proposals) {
+ log_error("message_add_sa_payload: calloc (%d, %lu) "
+ "failed", nprotos,
+ (unsigned long)sizeof *proposals);
+ goto cleanup;
+ }
+ proposal_lens = calloc(nprotos, sizeof *proposal_lens);
+ if (!proposal_lens) {
+ log_error("message_add_sa_payload: calloc (%d, %lu) "
+ "failed", nprotos,
+ (unsigned long)sizeof *proposal_lens);
+ goto cleanup;
+ }
+ /* Pick out the chosen transforms. */
+ for (proto = TAILQ_FIRST(&sa->protos), i = 0; proto;
+ proto = TAILQ_NEXT(proto, link), i++) {
+ transform_lens[i] =
+ GET_ISAKMP_GEN_LENGTH(proto->chosen->p);
+ transforms[i] = malloc(transform_lens[i]);
+ if (!transforms[i]) {
+ log_error("message_add_sa_payload: malloc "
+ "(%lu) failed",
+ (unsigned long)transform_lens[i]);
+ goto cleanup;
+ }
+ /* Get incoming SPI from application. */
+ if (doi->get_spi) {
+ spi = doi->get_spi(&spi_sz,
+ GET_ISAKMP_PROP_PROTO(proto->chosen->context->p),
+ msg);
+ if (spi_sz && !spi)
+ goto cleanup;
+ proto->spi[1] = spi;
+ proto->spi_sz[1] = spi_sz;
+ } else
+ spi_sz = 0;
+
+ proposal_lens[i] = ISAKMP_PROP_SPI_OFF + spi_sz;
+ proposals[i] = malloc(proposal_lens[i]);
+ if (!proposals[i]) {
+ log_error("message_add_sa_payload: malloc "
+ "(%lu) failed",
+ (unsigned long)proposal_lens[i]);
+ goto cleanup;
+ }
+ memcpy(transforms[i], proto->chosen->p,
+ transform_lens[i]);
+ memcpy(proposals[i], proto->chosen->context->p,
+ ISAKMP_PROP_SPI_OFF);
+ SET_ISAKMP_PROP_NTRANSFORMS(proposals[i], 1);
+ SET_ISAKMP_PROP_SPI_SZ(proposals[i], spi_sz);
+ if (spi_sz)
+ memcpy(proposals[i] + ISAKMP_PROP_SPI_OFF, spi,
+ spi_sz);
+ extra_sa_len += proposal_lens[i] + transform_lens[i];
+ }
+
+ /*
+ * Add the payloads. As this is a SA, we need to recompute the
+ * lengths of the payloads containing others. We also need to
+ * reset these payload's "next payload type" field.
+ */
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_SA, sa_buf,
+ sa_len, 1))
+ goto cleanup;
+ SET_ISAKMP_GEN_LENGTH(sa_buf, sa_len + extra_sa_len);
+ sa_buf = 0;
+
+ saved_nextp_sa = msg->nextp;
+ for (proto = TAILQ_FIRST(&sa->protos), i = 0; proto;
+ proto = TAILQ_NEXT(proto, link), i++) {
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL,
+ proposals[i], proposal_lens[i], i > 1))
+ goto cleanup;
+ SET_ISAKMP_GEN_LENGTH(proposals[i], proposal_lens[i] +
+ transform_lens[i]);
+ proposals[i] = 0;
+
+ saved_nextp_prop = msg->nextp;
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM,
+ transforms[i], transform_lens[i], 0))
+ goto cleanup;
+ msg->nextp = saved_nextp_prop;
+ transforms[i] = 0;
+ }
+ msg->nextp = saved_nextp_sa;
+
+ /* Free the temporary allocations made above. */
+ free(transforms);
+ free(transform_lens);
+ free(proposals);
+ free(proposal_lens);
+ }
+ return 0;
+
+cleanup:
+ if (sa_buf)
+ free(sa_buf);
+ for (i = 0; i < nprotos; i++) {
+ if (transforms[i])
+ free(transforms[i]);
+ if (proposals[i])
+ free(proposals[i]);
+ }
+ if (transforms)
+ free(transforms);
+ if (transform_lens)
+ free(transform_lens);
+ if (proposals)
+ free(proposals);
+ if (proposal_lens)
+ free(proposal_lens);
+ return -1;
+}
+
+/*
+ * Return a copy of MSG's constants starting from OFFSET and stash the size
+ * in SZP. It is the callers responsibility to free this up.
+ */
+u_int8_t *
+message_copy(struct message *msg, size_t offset, size_t *szp)
+{
+ int skip = 0;
+ size_t i, sz = 0;
+ ssize_t start = -1;
+ u_int8_t *buf, *p;
+
+ /* Calculate size of message and where we want to start to copy. */
+ for (i = 1; i < msg->iovlen; i++) {
+ sz += msg->iov[i].iov_len;
+ if (sz <= offset)
+ skip = i;
+ else if (start < 0)
+ start = offset - (sz - msg->iov[i].iov_len);
+ }
+
+ /* Allocate and copy. */
+ *szp = sz - offset;
+ buf = malloc(*szp);
+ if (!buf)
+ return 0;
+ p = buf;
+ for (i = skip + 1; i < msg->iovlen; i++) {
+ memcpy(p, (u_int8_t *) msg->iov[i].iov_base + start,
+ msg->iov[i].iov_len - start);
+ p += msg->iov[i].iov_len - start;
+ start = 0;
+ }
+ return buf;
+}
+
+/* Register a post-send function POST_SEND with message MSG. */
+int
+message_register_post_send(struct message *msg,
+ void (*post_send)(struct message *))
+{
+ struct post_send *node;
+
+ node = malloc(sizeof *node);
+ if (!node)
+ return -1;
+ node->func = post_send;
+ TAILQ_INSERT_TAIL(&msg->post_send, node, link);
+ return 0;
+}
+
+/* Run the post-send functions of message MSG. */
+void
+message_post_send(struct message *msg)
+{
+ struct post_send *node;
+
+ while ((node = TAILQ_FIRST(&msg->post_send)) != 0) {
+ TAILQ_REMOVE(&msg->post_send, node, link);
+ node->func(msg);
+ free(node);
+ }
+}
+
+/* Initialize and populate payload_map[]. */
+void
+message_init(void)
+{
+ u_int8_t i;
+
+ memset(&payload_map, 0, sizeof payload_map);
+
+ payload_index_max = sizeof payload_revmap / sizeof payload_revmap[0];
+ for (i = 0; i < payload_index_max; i++) {
+ payload_map[payload_revmap[i]] = i;
+ LOG_DBG((LOG_MESSAGE, 95, "message_init: payload_map[%d] = %d",
+ payload_revmap[i], i));
+ }
+}
+
+struct payload *
+payload_first(struct message *msg, u_int8_t payload)
+{
+ if (payload_map[payload])
+ return TAILQ_FIRST(&msg->payload[payload_map[payload]]);
+ else
+ return 0;
+}
+
+struct payload *
+payload_last(struct message *msg, u_int8_t payload)
+{
+ if (payload_map[payload])
+ return TAILQ_LAST(&msg->payload[payload_map[payload]],
+ payload_head);
+ else
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/message.h b/keyexchange/isakmpd-20041012/message.h
new file mode 100644
index 0000000..14b1d9a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/message.h
@@ -0,0 +1,205 @@
+/* $OpenBSD: message.h,v 1.22 2004/08/10 15:59:10 ho Exp $ */
+/* $EOM: message.h,v 1.51 2000/10/10 12:36:39 provos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2001, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MESSAGE_H_
+#define _MESSAGE_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include "isakmp.h"
+
+struct event;
+struct message;
+struct proto;
+struct sa;
+struct transport;
+
+struct payload {
+ /* Link all payloads of the same type through here. */
+ TAILQ_ENTRY(payload) link;
+
+ /* The pointer to the actual payload data. */
+ u_int8_t *p;
+
+ /*
+ * A pointer to the parent payload, used for proposal and transform
+ * payloads.
+ */
+ struct payload *context;
+
+ /* Payload flags described below. */
+ int flags;
+};
+
+/* Payload flags. */
+
+/*
+ * Set this when a payload has been handled, so we later can sweep over
+ * unhandled ones.
+ */
+#define PL_MARK 1
+
+/* A post-send chain of functions to be called. */
+struct post_send {
+ /* Link to the next function in the chain. */
+ TAILQ_ENTRY(post_send) link;
+
+ /* The actual function. */
+ void (*func) (struct message *);
+};
+
+struct message {
+ /* Link message in send queues via this link. */
+ TAILQ_ENTRY(message) link;
+
+ /* Message flags described below. */
+ u_int flags;
+
+ /*
+ * This is the transport the message either arrived on or will be sent
+ * to.
+ */
+ struct transport *transport;
+
+ /*
+ * This is the ISAKMP SA protecting this message.
+ * XXX Needs to be redone to some keystate pointer or something.
+ */
+ struct sa *isakmp_sa;
+
+ /* This is the exchange where this message appears. */
+ struct exchange *exchange;
+
+ /*
+ * A segmented buffer structure holding the messages raw contents. On
+ * input only segment 0 will be filled, holding all of the message.
+ * On output, as long as the message body is unencrypted each segment
+ * will be one payload, after encryption segment 0 will be the
+ * unencrypted header, and segment 1 will be the encrypted payloads,
+ * all of them.
+ */
+ struct iovec *iov;
+
+ /* The segment count. */
+ u_int iovlen;
+
+ /* Pointer to the last "next payload" field. */
+ u_int8_t *nextp;
+
+ /* "Smart" pointers to each payload, sorted by type. */
+ TAILQ_HEAD(payload_head, payload) *payload;
+
+ /* Number of times this message has been sent. */
+ int xmits;
+
+ /* The timeout event causing retransmission of this message. */
+ struct event *retrans;
+
+ /* The (possibly encrypted) message text, used for duplicate testing. */
+ u_int8_t *orig;
+ size_t orig_sz;
+
+ /*
+ * Extra baggage needed to travel with the message. Used transiently
+ * in context sensitive ways.
+ */
+ void *extra;
+
+ /*
+ * Hooks for stuff needed to be done after the message has gone out to
+ * the wire.
+ */
+ TAILQ_HEAD(post_send_head, post_send) post_send;
+};
+
+/* Message flags. */
+
+/*
+ * This is the last message of an exchange, meaning it should not be
+ * retransmitted other than if we see duplicates from our peer's last
+ * message.
+ */
+#define MSG_LAST 0x01
+
+/* The message has already been encrypted. */
+#define MSG_ENCRYPTED 0x02
+
+/* The message is on the send queue. */
+#define MSG_IN_TRANSIT 0x04
+
+/* This message should be kept on the prioritized sendq. */
+#define MSG_PRIORITIZED 0x08
+
+/* This message has successfully been authenticated. */
+#define MSG_AUTHENTICATED 0x10
+
+TAILQ_HEAD(msg_head, message);
+
+/* The number of different ISAKMP payloads supported. */
+extern u_int8_t payload_index_max;
+
+extern int message_add_payload(struct message *, u_int8_t, u_int8_t *,
+ size_t, int);
+extern int message_add_sa_payload(struct message *);
+extern struct message *message_alloc(struct transport *, u_int8_t *, size_t);
+extern struct message *message_alloc_reply(struct message *);
+extern u_int8_t *message_copy(struct message *, size_t, size_t *);
+extern void message_drop(struct message *, int, struct proto *, int, int);
+extern void message_dump_raw(char *, struct message *, int);
+extern void message_free(struct message *);
+extern void message_init(void);
+extern int message_negotiate_sa(struct message *,
+ int (*)(struct exchange *, struct sa *, struct sa *));
+extern int message_recv(struct message *);
+extern int message_register_post_send(struct message *,
+ void (*) (struct message *));
+extern void message_post_send(struct message *);
+extern void message_send(struct message *);
+extern void message_send_expire(struct message *);
+extern void message_send_delete(struct sa *);
+extern int message_send_info(struct message *);
+extern void message_send_notification(struct message *, struct sa *,
+ u_int16_t, struct proto *, int);
+extern void message_setup_header(struct message *, u_int8_t, u_int8_t,
+ u_int8_t *);
+struct payload *payload_first(struct message *, u_int8_t);
+struct payload *payload_last(struct message *, u_int8_t);
+
+#if defined (USE_DPD)
+extern void message_send_dpd_notify(struct sa*, u_int16_t, u_int32_t);
+#endif
+
+#endif /* _MESSAGE_H_ */
diff --git a/keyexchange/isakmpd-20041012/monitor.c b/keyexchange/isakmpd-20041012/monitor.c
new file mode 100644
index 0000000..bd14005
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/monitor.c
@@ -0,0 +1,1174 @@
+/* $OpenBSD: monitor.c,v 1.29 2004/08/12 11:21:07 hshoexer Exp $ */
+
+/*
+ * Copyright (c) 2003 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if defined (USE_POLICY)
+#include <regex.h>
+#include <keynote.h>
+#endif
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "log.h"
+#include "monitor.h"
+#include "policy.h"
+#include "ui.h"
+#include "util.h"
+#include "pf_key_v2.h"
+
+struct monitor_state {
+ pid_t pid;
+ int s;
+ char root[MAXPATHLEN];
+} m_state;
+
+volatile sig_atomic_t sigchlded = 0;
+extern volatile sig_atomic_t sigtermed;
+static volatile sig_atomic_t cur_state = STATE_INIT;
+
+/* Private functions. */
+int m_write_int32(int, int32_t);
+int m_write_raw(int, char *, size_t);
+int m_read_int32(int, int32_t *);
+int m_read_raw(int, char *, size_t);
+void m_flush(int);
+
+static void m_priv_getfd(int);
+static void m_priv_getsocket(int);
+static void m_priv_setsockopt(int);
+static void m_priv_bind(int);
+static int m_priv_local_sanitize_path(char *, size_t, int);
+static int m_priv_check_sockopt(int, int);
+static int m_priv_check_bind(const struct sockaddr *, socklen_t);
+static void m_priv_increase_state(int);
+static void m_priv_test_state(int);
+
+static void m_priv_ui_init(int);
+static void m_priv_pfkey_open(int);
+
+/*
+ * Public functions, unprivileged.
+ */
+
+/* Setup monitor context, fork, drop child privs. */
+pid_t
+monitor_init(int debug)
+{
+ struct passwd *pw;
+ int p[2];
+
+ memset(&m_state, 0, sizeof m_state);
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) != 0)
+ log_fatal("monitor_init: socketpair() failed");
+
+ pw = getpwnam(ISAKMPD_PRIVSEP_USER);
+ if (pw == NULL)
+ log_fatal("monitor_init: getpwnam(\"%s\") failed",
+ ISAKMPD_PRIVSEP_USER);
+
+ m_state.pid = fork();
+ m_state.s = p[m_state.pid ? 1 : 0];
+ strlcpy(m_state.root, pw->pw_dir, sizeof m_state.root);
+
+ LOG_DBG((LOG_SYSDEP, 30, "monitor_init: pid %d my fd %d", m_state.pid,
+ m_state.s));
+
+ /* The child process should drop privileges now. */
+ if (!m_state.pid) {
+ if (chroot(pw->pw_dir) != 0 || chdir("/") != 0)
+ log_fatal("monitor_init: chroot failed");
+
+ if (setgid(pw->pw_gid) != 0)
+ log_fatal("monitor_init: setgid(%d) failed",
+ pw->pw_gid);
+
+ if (setuid(pw->pw_uid) != 0)
+ log_fatal("monitor_init: setuid(%d) failed",
+ pw->pw_uid);
+
+ LOG_DBG((LOG_MISC, 10,
+ "monitor_init: privileges dropped for child process"));
+ } else {
+ setproctitle("monitor [priv]");
+ }
+
+
+ /* With "-dd", stop and wait here. For gdb "attach" etc. */
+ if (debug > 1) {
+ log_print("monitor_init: stopped %s PID %d fd %d%s",
+ m_state.pid ? "priv" : "child", getpid(), m_state.s,
+ m_state.pid ? ", waiting for SIGCONT" : "");
+ kill(getpid(), SIGSTOP); /* Wait here for SIGCONT. */
+ if (m_state.pid)
+ kill(m_state.pid, SIGCONT); /* Continue child. */
+ }
+
+ return m_state.pid;
+}
+
+void
+monitor_exit(int code)
+{
+ if (m_state.pid != 0)
+ kill(m_state.pid, SIGKILL);
+
+ exit(code);
+}
+
+void
+monitor_ui_init(void)
+{
+ int32_t err;
+
+ if (m_write_int32(m_state.s, MONITOR_UI_INIT))
+ goto errout;
+
+ if (m_read_int32(m_state.s, &err))
+ goto errout;
+
+ if (err != 0) {
+ log_fatal("monitor_ui_init: parent could not create FIFO "
+ "\"%s\"", ui_fifo);
+ exit(1);
+ }
+
+ ui_socket = mm_receive_fd(m_state.s);
+ if (ui_socket < 0)
+ log_fatal("monitor_ui_init: parent could not create FIFO "
+ "\"%s\"", ui_fifo);
+
+ return;
+
+errout:
+ log_error("monitor_ui_init: problem talking to privileged process");
+ return;
+}
+
+int
+monitor_pf_key_v2_open(void)
+{
+ int32_t err;
+
+ if (m_write_int32(m_state.s, MONITOR_PFKEY_OPEN))
+ goto errout;
+
+ if (m_read_int32(m_state.s, &err))
+ goto errout;
+
+ if (err < 0) {
+ log_error("monitor_pf_key_v2_open: parent could not create "
+ "PF_KEY socket");
+ return -1;
+ }
+
+ pf_key_v2_socket = mm_receive_fd(m_state.s);
+ if (pf_key_v2_socket < 0) {
+ log_error("monitor_pf_key_v2_open: mm_receive_fd() failed: %s",
+ strerror(errno));
+ return -1;
+ }
+ return pf_key_v2_socket;
+
+errout:
+ log_error("monitor_pf_key_v2_open: problem talking to privileged "
+ "process");
+ return -1;
+}
+
+int
+monitor_open(const char *path, int flags, mode_t mode)
+{
+ int fd, mode32 = (int32_t) mode;
+ int32_t err;
+ char realpath[MAXPATHLEN];
+
+ if (path[0] == '/')
+ strlcpy(realpath, path, sizeof realpath);
+ else
+ snprintf(realpath, sizeof realpath, "%s/%s", m_state.root,
+ path);
+
+ /* Write data to priv process. */
+ if (m_write_int32(m_state.s, MONITOR_GET_FD))
+ goto errout;
+
+ if (m_write_raw(m_state.s, realpath, strlen(realpath) + 1))
+ goto errout;
+
+ if (m_write_int32(m_state.s, flags))
+ goto errout;
+
+ if (m_write_int32(m_state.s, mode32))
+ goto errout;
+
+ if (m_read_int32(m_state.s, &err))
+ goto errout;
+
+ if (err != 0) {
+ errno = (int) err;
+ return -1;
+ }
+ /* Wait for response. */
+ fd = mm_receive_fd(m_state.s);
+ if (fd < 0) {
+ log_error("monitor_open: mm_receive_fd () failed: %s",
+ strerror(errno));
+ return -1;
+ }
+ return fd;
+
+errout:
+ log_error("monitor_open: problem talking to privileged process");
+ return -1;
+}
+
+FILE *
+monitor_fopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ int fd, flags = 0, saved_errno;
+ mode_t mask, cur_umask;
+
+ /* Only the child process is supposed to run this. */
+ if (m_state.pid)
+ log_fatal("[priv] bad call to monitor_fopen");
+
+ switch (mode[0]) {
+ case 'r':
+ flags = (mode[1] == '+' ? O_RDWR : O_RDONLY);
+ break;
+ case 'w':
+ flags = (mode[1] == '+' ? O_RDWR : O_WRONLY) | O_CREAT |
+ O_TRUNC;
+ break;
+ case 'a':
+ flags = (mode[1] == '+' ? O_RDWR : O_WRONLY) | O_CREAT |
+ O_APPEND;
+ break;
+ default:
+ log_fatal("monitor_fopen: bad call");
+ }
+
+ cur_umask = umask(0);
+ (void)umask(cur_umask);
+ mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ mask &= ~cur_umask;
+
+ fd = monitor_open(path, flags, mask);
+ if (fd < 0)
+ return NULL;
+
+ /* Got the fd, attach a FILE * to it. */
+ fp = fdopen(fd, mode);
+ if (!fp) {
+ log_error("monitor_fopen: fdopen() failed");
+ saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+ return NULL;
+ }
+ return fp;
+}
+
+int
+monitor_stat(const char *path, struct stat *sb)
+{
+ int fd, r, saved_errno;
+
+ /* O_NONBLOCK is needed for stat'ing fifos. */
+ fd = monitor_open(path, O_RDONLY | O_NONBLOCK, 0);
+ if (fd < 0)
+ return -1;
+
+ r = fstat(fd, sb);
+ saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+ return r;
+}
+
+int
+monitor_socket(int domain, int type, int protocol)
+{
+ int s;
+ int32_t err;
+
+ if (m_write_int32(m_state.s, MONITOR_GET_SOCKET))
+ goto errout;
+
+ if (m_write_int32(m_state.s, (int32_t)domain))
+ goto errout;
+
+ if (m_write_int32(m_state.s, (int32_t)type))
+ goto errout;
+
+ if (m_write_int32(m_state.s, (int32_t)protocol))
+ goto errout;
+
+ if (m_read_int32(m_state.s, &err))
+ goto errout;
+
+ if (err != 0) {
+ errno = (int)err;
+ return -1;
+ }
+ /* Read result. */
+ s = mm_receive_fd(m_state.s);
+ if (s < 0) {
+ log_error("monitor_socket: mm_receive_fd () failed: %s",
+ strerror(errno));
+ return -1;
+ }
+ return s;
+
+errout:
+ log_error("monitor_socket: problem talking to privileged process");
+ return -1;
+}
+
+int
+monitor_setsockopt(int s, int level, int optname, const void *optval,
+ socklen_t optlen)
+{
+ int32_t ret, err;
+
+ if (m_write_int32(m_state.s, MONITOR_SETSOCKOPT))
+ goto errout;
+ if (mm_send_fd(m_state.s, s))
+ goto errout;
+
+ if (m_write_int32(m_state.s, (int32_t)level))
+ goto errout;
+ if (m_write_int32(m_state.s, (int32_t)optname))
+ goto errout;
+ if (m_write_int32(m_state.s, (int32_t)optlen))
+ goto errout;
+ if (m_write_raw(m_state.s, (char *)optval, (size_t)optlen))
+ goto errout;
+
+ if (m_read_int32(m_state.s, &err))
+ goto errout;
+
+ if (err != 0)
+ errno = (int)err;
+
+ if (m_read_int32(m_state.s, &ret))
+ goto errout;
+
+ return (int)ret;
+
+errout:
+ log_print("monitor_setsockopt: read/write error");
+ return -1;
+}
+
+int
+monitor_bind(int s, const struct sockaddr *name, socklen_t namelen)
+{
+ int32_t ret, err;
+
+ if (m_write_int32(m_state.s, MONITOR_BIND))
+ goto errout;
+ if (mm_send_fd(m_state.s, s))
+ goto errout;
+
+ if (m_write_int32(m_state.s, (int32_t)namelen))
+ goto errout;
+ if (m_write_raw(m_state.s, (char *)name, (size_t)namelen))
+ goto errout;
+
+ if (m_read_int32(m_state.s, &err))
+ goto errout;
+
+ if (err != 0)
+ errno = (int)err;
+
+ if (m_read_int32(m_state.s, &ret))
+ goto errout;
+
+ return (int)ret;
+
+errout:
+ log_print("monitor_bind: read/write error");
+ return -1;
+}
+
+struct monitor_dirents *
+monitor_opendir(const char *path)
+{
+ char *buf, *cp;
+ size_t bufsize;
+ int fd, nbytes, entries;
+ long base;
+ struct stat sb;
+ struct dirent *dp;
+ struct monitor_dirents *direntries;
+
+ fd = monitor_open(path, 0, O_RDONLY);
+ if (fd < 0) {
+ log_error("monitor_opendir: opendir(\"%s\") failed", path);
+ return NULL;
+ }
+ /* Now build a list with all dirents from fd. */
+ if (fstat(fd, &sb) < 0) {
+ (void)close(fd);
+ return NULL;
+ }
+ if (!S_ISDIR(sb.st_mode)) {
+ (void)close(fd);
+ errno = EACCES;
+ return NULL;
+ }
+ bufsize = sb.st_size;
+ if (bufsize < sb.st_blksize)
+ bufsize = sb.st_blksize;
+
+ buf = calloc(bufsize, sizeof(char));
+ if (buf == NULL) {
+ (void)close(fd);
+ errno = EACCES;
+ return NULL;
+ }
+ nbytes = getdirentries(fd, buf, bufsize, &base);
+ if (nbytes <= 0) {
+ (void)close(fd);
+ free(buf);
+ errno = EACCES;
+ return NULL;
+ }
+ (void)close(fd);
+
+ for (entries = 0, cp = buf; cp < buf + nbytes;) {
+ dp = (struct dirent *)cp;
+ cp += dp->d_reclen;
+ entries++;
+ }
+
+ direntries = calloc(1, sizeof(struct monitor_dirents));
+ if (direntries == NULL) {
+ free(buf);
+ errno = EACCES;
+ return NULL;
+ }
+ direntries->dirents = calloc(entries + 1, sizeof(struct dirent *));
+ if (direntries->dirents == NULL) {
+ free(buf);
+ free(direntries);
+ errno = EACCES;
+ return NULL;
+ }
+ direntries->current = 0;
+
+ for (entries = 0, cp = buf; cp < buf + nbytes;) {
+ dp = (struct dirent *)cp;
+ direntries->dirents[entries++] = dp;
+ cp += dp->d_reclen;
+ }
+ direntries->dirents[entries] = NULL;
+
+ return direntries;
+}
+
+struct dirent *
+monitor_readdir(struct monitor_dirents *direntries)
+{
+ if (direntries->dirents[direntries->current] != NULL)
+ return direntries->dirents[direntries->current++];
+
+ return NULL;
+}
+
+int
+monitor_closedir(struct monitor_dirents *direntries)
+{
+ free(direntries->dirents);
+ free(direntries);
+
+ return 0;
+}
+
+void
+monitor_init_done(void)
+{
+ if (m_write_int32(m_state.s, MONITOR_INIT_DONE))
+ log_print("monitor_init_done: read/write error");
+
+ return;
+}
+
+/*
+ * Start of code running with privileges (the monitor process).
+ */
+
+/* Help functions for monitor_loop(). */
+static void
+monitor_got_sigchld(int sig)
+{
+ sigchlded = 1;
+}
+
+static void
+sig_pass_to_chld(int sig)
+{
+ int oerrno = errno;
+
+ if (m_state.pid != -1)
+ kill(m_state.pid, sig);
+ errno = oerrno;
+}
+
+/* This function is where the privileged process waits(loops) indefinitely. */
+void
+monitor_loop(int debug)
+{
+ pid_t pid;
+ fd_set *fds;
+ size_t fdsn;
+ int status, n, maxfd;
+
+ if (!debug)
+ log_to(0);
+
+ maxfd = m_state.s + 1;
+
+ fdsn = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
+ fds = (fd_set *)malloc(fdsn);
+ if (!fds) {
+ kill(m_state.pid, SIGTERM);
+ log_fatal("monitor_loop: malloc (%lu) failed",
+ (unsigned long)fdsn);
+ return;
+ }
+ /* If the child dies, we should shutdown also. */
+ signal(SIGCHLD, monitor_got_sigchld);
+
+ /* SIGHUP, SIGUSR1 and SIGUSR2 will be forwarded to child. */
+ signal(SIGHUP, sig_pass_to_chld);
+ signal(SIGUSR1, sig_pass_to_chld);
+ signal(SIGUSR2, sig_pass_to_chld);
+
+ while (cur_state < STATE_QUIT) {
+ /*
+ * Currently, there is no need for us to hang around if the
+ * child is in the process of shutting down.
+ */
+ if (sigtermed) {
+ m_priv_increase_state(STATE_QUIT);
+ kill(m_state.pid, SIGTERM);
+ break;
+ }
+
+ if (sigchlded) {
+ do {
+ pid = waitpid(m_state.pid, &status, WNOHANG);
+ } while (pid == -1 && errno == EINTR);
+
+ if (pid == m_state.pid && (WIFEXITED(status) ||
+ WIFSIGNALED(status))) {
+ m_priv_increase_state(STATE_QUIT);
+ break;
+ }
+ }
+
+ memset(fds, 0, fdsn);
+ FD_SET(m_state.s, fds);
+
+ n = select(maxfd, fds, NULL, NULL, NULL);
+ if (n == -1) {
+ if (errno != EINTR) {
+ log_error("select");
+ sleep(1);
+ }
+ } else if (n)
+ if (FD_ISSET(m_state.s, fds)) {
+ int32_t msgcode;
+ if (m_read_int32(m_state.s, &msgcode))
+ m_flush(m_state.s);
+ else
+ switch (msgcode) {
+ case MONITOR_GET_FD:
+ m_priv_getfd(m_state.s);
+ break;
+
+ case MONITOR_UI_INIT:
+ LOG_DBG((LOG_MISC, 80,
+ "%s: MONITOR_UI_INIT",
+ __func__));
+ m_priv_test_state(STATE_INIT);
+ m_priv_ui_init(m_state.s);
+ break;
+
+ case MONITOR_PFKEY_OPEN:
+ LOG_DBG((LOG_MISC, 80,
+ "%s: MONITOR_PFKEY_OPEN",
+ __func__));
+ m_priv_test_state(STATE_INIT);
+ m_priv_pfkey_open(m_state.s);
+ break;
+
+ case MONITOR_GET_SOCKET:
+ LOG_DBG((LOG_MISC, 80,
+ "%s: MONITOR_GET_SOCKET",
+ __func__));
+ m_priv_test_state(STATE_INIT);
+ m_priv_getsocket(m_state.s);
+ break;
+
+ case MONITOR_SETSOCKOPT:
+ LOG_DBG((LOG_MISC, 80,
+ "%s: MONITOR_SETSOCKOPT",
+ __func__));
+ m_priv_test_state(STATE_INIT);
+ m_priv_setsockopt(m_state.s);
+ break;
+
+ case MONITOR_BIND:
+ LOG_DBG((LOG_MISC, 80,
+ "%s: MONITOR_BIND",
+ __func__));
+ m_priv_test_state(STATE_INIT);
+ m_priv_bind(m_state.s);
+ break;
+
+ case MONITOR_INIT_DONE:
+ LOG_DBG((LOG_MISC, 80,
+ "%s: MONITOR_INIT_DONE",
+ __func__));
+ m_priv_test_state(STATE_INIT);
+ m_priv_increase_state(
+ STATE_RUNNING);
+ break;
+
+ case MONITOR_SHUTDOWN:
+ LOG_DBG((LOG_MISC, 80,
+ "%s: MONITOR_SHUTDOWN",
+ __func__));
+ m_priv_increase_state(
+ STATE_QUIT);
+ break;
+
+ default:
+ log_print("monitor_loop: "
+ "got unknown code %d",
+ msgcode);
+ }
+ }
+ }
+
+ free(fds);
+ exit(0);
+}
+
+
+/* Privileged: called by monitor_loop. */
+static void
+m_priv_ui_init(int s)
+{
+ int32_t err;
+
+ ui_init();
+
+ if (ui_socket >= 0)
+ err = 0;
+ else
+ err = -1;
+
+ if (m_write_int32(s, err))
+ goto errout;
+
+ if (ui_socket >= 0 && mm_send_fd(s, ui_socket)) {
+ close(ui_socket);
+ goto errout;
+ }
+
+ /* In case of stdin, we do not close the socket. */
+ if (ui_socket > 0)
+ close(ui_socket);
+ return;
+
+errout:
+ log_error("m_priv_ui_init: read/write operation failed");
+ return;
+}
+
+/* Privileged: called by monitor_loop. */
+static void
+m_priv_pfkey_open(int s)
+{
+ int fd;
+ int32_t err;
+
+ fd = pf_key_v2_open();
+
+ if (fd < 0)
+ err = -1;
+ else
+ err = 0;
+
+ if (m_write_int32(s, err))
+ goto errout;
+
+ if (fd > 0 && mm_send_fd(s, fd)) {
+ close(fd);
+ goto errout;
+ }
+ close(fd);
+
+ return;
+
+errout:
+ log_error("m_priv_pfkey_open: read/write operation failed");
+ return;
+}
+
+/* Privileged: called by monitor_loop. */
+static void
+m_priv_getfd(int s)
+{
+ char path[MAXPATHLEN];
+ int32_t v, err;
+ int flags;
+ mode_t mode;
+
+ /*
+ * We expect the following data on the socket:
+ * u_int32_t pathlen
+ * <variable> path
+ * u_int32_t flags
+ * u_int32_t mode
+ */
+
+ if (m_read_raw(s, path, MAXPATHLEN))
+ goto errout;
+
+ if (m_read_int32(s, &v))
+ goto errout;
+ flags = (int)v;
+
+ if (m_read_int32(s, &v))
+ goto errout;
+ mode = (mode_t) v;
+
+ if (m_priv_local_sanitize_path(path, sizeof path, flags) != 0) {
+ err = EACCES;
+ v = -1;
+ } else {
+ err = 0;
+ v = (int32_t)open(path, flags, mode);
+ if (v < 0)
+ err = (int32_t)errno;
+ }
+
+ if (m_write_int32(s, err))
+ goto errout;
+
+ if (v > 0 && mm_send_fd(s, v)) {
+ close(v);
+ goto errout;
+ }
+ close(v);
+ return;
+
+errout:
+ log_error("m_priv_getfd: read/write operation failed");
+ return;
+}
+
+/* Privileged: called by monitor_loop. */
+static void
+m_priv_getsocket(int s)
+{
+ int domain, type, protocol;
+ int32_t v, err;
+
+ if (m_read_int32(s, &v))
+ goto errout;
+ domain = (int)v;
+
+ if (m_read_int32(s, &v))
+ goto errout;
+ type = (int)v;
+
+ if (m_read_int32(s, &v))
+ goto errout;
+ protocol = (int)v;
+
+ err = 0;
+ v = (int32_t)socket(domain, type, protocol);
+ if (v < 0)
+ err = (int32_t)errno;
+
+ if (m_write_int32(s, err))
+ goto errout;
+
+ if (v > 0 && mm_send_fd(s, v)) {
+ close(v);
+ goto errout;
+ }
+ close(v);
+ return;
+
+errout:
+ log_error("m_priv_getsocket: read/write operation failed");
+ return;
+}
+
+/* Privileged: called by monitor_loop. */
+static void
+m_priv_setsockopt(int s)
+{
+ int sock, level, optname;
+ char *optval = 0;
+ socklen_t optlen;
+ int32_t v, err;
+
+ sock = mm_receive_fd(s);
+ if (sock < 0)
+ goto errout;
+
+ if (m_read_int32(s, &level))
+ goto errout;
+
+ if (m_read_int32(s, &optname))
+ goto errout;
+
+ if (m_read_int32(s, &optlen))
+ goto errout;
+
+ optval = (char *)malloc(optlen);
+ if (!optval)
+ goto errout;
+
+ if (m_read_raw(s, optval, optlen))
+ goto errout;
+
+ if (m_priv_check_sockopt(level, optname) != 0) {
+ err = EACCES;
+ v = -1;
+ } else {
+ err = 0;
+ v = (int32_t)setsockopt(sock, level, optname, optval, optlen);
+ if (v < 0)
+ err = (int32_t)errno;
+ }
+
+ close(sock);
+ sock = -1;
+
+ if (m_write_int32(s, err))
+ goto errout;
+
+ if (m_write_int32(s, v))
+ goto errout;
+
+ free(optval);
+ return;
+
+errout:
+ log_print("m_priv_setsockopt: read/write error");
+ if (optval)
+ free(optval);
+ if (sock >= 0)
+ close(sock);
+ return;
+}
+
+/* Privileged: called by monitor_loop. */
+static void
+m_priv_bind(int s)
+{
+ int sock;
+ struct sockaddr *name = 0;
+ socklen_t namelen;
+ int32_t v, err;
+
+ sock = mm_receive_fd(s);
+ if (sock < 0)
+ goto errout;
+
+ if (m_read_int32(s, &v))
+ goto errout;
+ namelen = (socklen_t) v;
+
+ name = (struct sockaddr *)malloc(namelen);
+ if (!name)
+ goto errout;
+
+ if (m_read_raw(s, (char *)name, (size_t)namelen))
+ goto errout;
+
+ if (m_priv_check_bind(name, namelen) != 0) {
+ err = EACCES;
+ v = -1;
+ } else {
+ err = 0;
+ v = (int32_t)bind(sock, name, namelen);
+ if (v < 0) {
+ log_error("m_priv_bind: bind(%d,%p,%d) returned %d",
+ sock, name, namelen, v);
+ err = (int32_t)errno;
+ }
+ }
+
+ close(sock);
+ sock = -1;
+
+ if (m_write_int32(s, err))
+ goto errout;
+
+ if (m_write_int32(s, v))
+ goto errout;
+
+ free(name);
+ return;
+
+errout:
+ log_print("m_priv_bind: read/write error");
+ if (name)
+ free(name);
+ if (sock >= 0)
+ close(sock);
+ return;
+}
+
+/*
+ * Help functions, used by both privileged and unprivileged code
+ */
+
+/* Write a 32-bit value to a socket. */
+int
+m_write_int32(int s, int32_t value)
+{
+ u_int32_t v;
+
+ memcpy(&v, &value, sizeof v);
+ return (write(s, &v, sizeof v) == -1);
+}
+
+/* Write a number of bytes of data to a socket. */
+int
+m_write_raw(int s, char *data, size_t dlen)
+{
+ if (m_write_int32(s, (int32_t) dlen))
+ return 1;
+ return (write(s, data, dlen) == -1);
+}
+
+int
+m_read_int32(int s, int32_t *value)
+{
+ u_int32_t v;
+
+ if (read(s, &v, sizeof v) != sizeof v)
+ return 1;
+ memcpy(value, &v, sizeof v);
+ return 0;
+}
+
+int
+m_read_raw(int s, char *data, size_t maxlen)
+{
+ u_int32_t v;
+ int r;
+
+ if (m_read_int32(s, &v))
+ return 1;
+ if (v > maxlen)
+ return 1;
+ r = read(s, data, v);
+ return (r == -1);
+}
+
+/* Drain all available input on a socket. */
+void
+m_flush(int s)
+{
+ u_int8_t tmp;
+ int one = 1;
+
+ ioctl(s, FIONBIO, &one);/* Non-blocking */
+ while (read(s, &tmp, 1) > 0);
+ ioctl(s, FIONBIO, 0); /* Blocking */
+}
+
+/* Check that path/mode is permitted. */
+static int
+m_priv_local_sanitize_path(char *path, size_t pmax, int flags)
+{
+ char *p;
+
+ /*
+ * We only permit paths starting with
+ * /etc/isakmpd/ (read only)
+ * /var/run/ (rw)
+ */
+
+ if (strlen(path) < strlen("/var/run/"))
+ goto bad_path;
+
+ /* Any path containing '..' is invalid. */
+ for (p = path; *p && (p - path) < (int)pmax; p++)
+ if (*p == '.' && *(p + 1) == '.')
+ goto bad_path;
+
+ /* For any write-mode, only a few paths are permitted. */
+ if ((flags & O_ACCMODE) != O_RDONLY) {
+ if (strncmp("/var/run/", path, strlen("/var/run/")) == 0)
+ return 0;
+ goto bad_path;
+ }
+ /* Any other path is read-only. */
+ if (strncmp(ISAKMPD_ROOT, path, strlen(ISAKMPD_ROOT)) == 0 ||
+ strncmp("/var/run/", path, strlen("/var/run/")) == 0)
+ return 0;
+
+bad_path:
+ log_print("m_priv_local_sanitize_path: illegal path \"%.1023s\", "
+ "replaced with \"/dev/null\"", path);
+ strlcpy(path, "/dev/null", pmax);
+ return 1;
+}
+
+/* Check setsockopt */
+static int
+m_priv_check_sockopt(int level, int name)
+{
+ switch (level) {
+ /* These are allowed */
+ case SOL_SOCKET:
+ case IPPROTO_IP:
+ case IPPROTO_IPV6:
+ break;
+
+ default:
+ log_print("m_priv_check_sockopt: Illegal level %d", level);
+ return 1;
+ }
+
+ switch (name) {
+ /* These are allowed */
+ case SO_REUSEPORT:
+ case SO_REUSEADDR:
+ case IP_AUTH_LEVEL:
+ case IP_ESP_TRANS_LEVEL:
+ case IP_ESP_NETWORK_LEVEL:
+ case IP_IPCOMP_LEVEL:
+ case IPV6_AUTH_LEVEL:
+ case IPV6_ESP_TRANS_LEVEL:
+ case IPV6_ESP_NETWORK_LEVEL:
+ case IPV6_IPCOMP_LEVEL:
+ break;
+
+ default:
+ log_print("m_priv_check_sockopt: Illegal option name %d",
+ name);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Check bind */
+static int
+m_priv_check_bind(const struct sockaddr *sa, socklen_t salen)
+{
+ in_port_t port;
+
+ if (sa == NULL) {
+ log_print("NULL address");
+ return 1;
+ }
+ if (sysdep_sa_len((struct sockaddr *)sa) != salen) {
+ log_print("Length mismatch: %d %d",
+ (int)sysdep_sa_len((struct sockaddr *)sa), (int)salen);
+ return 1;
+ }
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (salen != sizeof(struct sockaddr_in)) {
+ log_print("Invalid inet address length");
+ return 1;
+ }
+ port = ((const struct sockaddr_in *)sa)->sin_port;
+ break;
+ case AF_INET6:
+ if (salen != sizeof(struct sockaddr_in6)) {
+ log_print("Invalid inet6 address length");
+ return 1;
+ }
+ port = ((const struct sockaddr_in6 *)sa)->sin6_port;
+ break;
+ default:
+ log_print("Unknown address family");
+ return 1;
+ }
+
+ port = ntohs(port);
+
+ if (port != ISAKMP_PORT_DEFAULT && port < 1024) {
+ log_print("Disallowed port %u", port);
+ return 1;
+ }
+ return 0;
+}
+
+/* Increase state into less permissive mode */
+static void
+m_priv_increase_state(int state)
+{
+ if (state <= cur_state)
+ log_print("m_priv_increase_state: attempt to decrase state "
+ "or match current state");
+ if (state < STATE_INIT || state > STATE_QUIT)
+ log_print("m_priv_increase_state: attempt to switch to "
+ "invalid state");
+ cur_state = state;
+}
+
+static void
+m_priv_test_state(int state)
+{
+ if (cur_state != state)
+ log_print("m_priv_test_state: Illegal state: %d != %d",
+ (int)cur_state, state);
+ return;
+}
diff --git a/keyexchange/isakmpd-20041012/monitor.h b/keyexchange/isakmpd-20041012/monitor.h
new file mode 100644
index 0000000..caea4ff
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/monitor.h
@@ -0,0 +1,104 @@
+/* $OpenBSD: monitor.h,v 1.11 2004/06/26 06:07:03 hshoexer Exp $ */
+
+/*
+ * Copyright (c) 2003 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _MONITOR_H_
+#define _MONITOR_H_
+
+#if defined (USE_PRIVSEP)
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <stdio.h>
+
+#define ISAKMPD_PRIVSEP_USER "_isakmpd"
+
+#define ISAKMP_PORT_DEFAULT 500
+
+enum monitor_reqtypes {
+ MONITOR_UI_INIT,
+ MONITOR_PFKEY_OPEN,
+ MONITOR_GET_FD,
+ MONITOR_GET_SOCKET,
+ MONITOR_SETSOCKOPT,
+ MONITOR_BIND,
+ MONITOR_MKFIFO,
+ MONITOR_INIT_DONE,
+ MONITOR_SHUTDOWN
+};
+
+enum priv_state {
+ STATE_INIT, /* just started */
+ STATE_RUNNING, /* running */
+ STATE_QUIT /* shutting down */
+};
+
+struct monitor_dirents {
+ int current;
+ struct dirent **dirents;
+};
+
+pid_t monitor_init(int);
+void monitor_loop(int);
+
+int mm_send_fd(int, int);
+int mm_receive_fd(int);
+
+FILE *monitor_fopen(const char *, const char *);
+int monitor_open(const char *, int, mode_t);
+int monitor_stat(const char *, struct stat *);
+int monitor_socket(int, int, int);
+int monitor_setsockopt(int, int, int, const void *, socklen_t);
+int monitor_bind(int, const struct sockaddr *, socklen_t);
+int monitor_mkfifo(const char *, mode_t);
+struct monitor_dirents *monitor_opendir(const char *);
+struct dirent *monitor_readdir(struct monitor_dirents *);
+int monitor_closedir(struct monitor_dirents *);
+void monitor_init_done(void);
+
+void monitor_ui_init(void);
+int monitor_pf_key_v2_open(void);
+void monitor_exit(int);
+
+#else /* !USE_PRIVSEP */
+
+#define monitor_fopen fopen
+#define monitor_open open
+#define monitor_stat stat
+#define monitor_socket socket
+#define monitor_setsockopt setsockopt
+#define monitor_bind bind
+#define monitor_mkfifo mkfifo
+#define monitor_opendir opendir
+#define monitor_readdir readdir
+#define monitor_closedir closedir
+
+#define monitor_ui_init ui_init
+#define monitor_exit exit
+#define monitor_pf_key_v2_open pf_key_v2_open
+
+#endif /* USE_PRIVSEP */
+#endif /* _MONITOR_H_ */
diff --git a/keyexchange/isakmpd-20041012/monitor_fdpass.c b/keyexchange/isakmpd-20041012/monitor_fdpass.c
new file mode 100644
index 0000000..0159653
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/monitor_fdpass.c
@@ -0,0 +1,112 @@
+/* $OpenBSD: monitor_fdpass.c,v 1.11 2004/10/01 04:08:45 jsg Exp $ */
+
+/*
+ * Copyright 2001 Niels Provos <provos@citi.umich.edu>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "log.h"
+#include "monitor.h"
+
+int
+mm_send_fd(int socket, int fd)
+{
+ struct msghdr msg;
+ char tmp[CMSG_SPACE(sizeof(int))], ch = '\0';
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ ssize_t n;
+
+ memset(&msg, 0, sizeof msg);
+ msg.msg_control = (caddr_t) tmp;
+ msg.msg_controllen = CMSG_LEN(sizeof(int));
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *(int *)CMSG_DATA(cmsg) = fd;
+
+ vec.iov_base = &ch;
+ vec.iov_len = 1;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+
+ if ((n = sendmsg(socket, &msg, 0)) == -1) {
+ log_error("mm_send_fd: sendmsg(%d)", fd);
+ return -1;
+ }
+ if (n != 1) {
+ log_error("mm_send_fd: sendmsg: expected sent 1 got %ld",
+ (long)n);
+ return -1;
+ }
+ return 0;
+}
+
+int
+mm_receive_fd(int socket)
+{
+ struct msghdr msg;
+ char tmp[CMSG_SPACE(sizeof(int))], ch;
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ ssize_t n;
+ int fd;
+
+ memset(&msg, 0, sizeof msg);
+ vec.iov_base = &ch;
+ vec.iov_len = 1;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = tmp;
+ msg.msg_controllen = sizeof tmp;
+
+ if ((n = recvmsg(socket, &msg, 0)) == -1) {
+ log_error("mm_receive_fd: recvmsg");
+ return -1;
+ }
+ if (n != 1) {
+ log_error("mm_receive_fd: recvmsg: expected received 1 got %ld",
+ (long)n);
+ return -1;
+ }
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg == NULL) {
+ log_error("mm_receive_fd: no message header");
+ return -1;
+ }
+ if (cmsg->cmsg_type != SCM_RIGHTS) {
+ log_error("mm_receive_fd: expected type %d got %d", SCM_RIGHTS,
+ cmsg->cmsg_type);
+ return -1;
+ }
+ fd = (*(int *)CMSG_DATA(cmsg));
+ return fd;
+}
diff --git a/keyexchange/isakmpd-20041012/nat_traversal.c b/keyexchange/isakmpd-20041012/nat_traversal.c
new file mode 100644
index 0000000..86d2d57
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/nat_traversal.c
@@ -0,0 +1,439 @@
+/* $OpenBSD: nat_traversal.c,v 1.17 2006/06/14 14:03:33 hshoexer Exp $ */
+
+/*
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ipsec.h"
+#include "isakmp_fld.h"
+#include "isakmp_num.h"
+#include "ipsec_num.h"
+#include "hash.h"
+#include "log.h"
+#include "message.h"
+#include "nat_traversal.h"
+#include "prf.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+#include "virtual.h"
+
+int disable_nat_t = 0;
+
+/*
+ * NAT-T capability of the other peer is determined by a particular vendor
+ * ID sent in the first message. This vendor ID string is supposed to be a
+ * MD5 hash of "RFC 3947".
+ *
+ * These seem to be the "well" known variants of this string in use by
+ * products today.
+ */
+
+static struct nat_t_cap isakmp_nat_t_cap[] = {
+ { VID_DRAFT_V2_N, EXCHANGE_FLAG_NAT_T_DRAFT,
+ "draft-ietf-ipsec-nat-t-ike-02\n", NULL, 0 },
+ { VID_DRAFT_V3, EXCHANGE_FLAG_NAT_T_DRAFT,
+ "draft-ietf-ipsec-nat-t-ike-03", NULL, 0 },
+ { VID_RFC3947, EXCHANGE_FLAG_NAT_T_RFC,
+ "RFC 3947", NULL, 0 },
+};
+
+#define NUMNATTCAP (sizeof isakmp_nat_t_cap / sizeof isakmp_nat_t_cap[0])
+
+/* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09. */
+#define NAT_T_KEEPALIVE_INTERVAL 20
+
+static int nat_t_setup_hashes(void);
+static int nat_t_add_vendor_payload(struct message *, struct nat_t_cap *);
+static int nat_t_add_nat_d(struct message *, struct sockaddr *);
+static int nat_t_match_nat_d_payload(struct message *, struct sockaddr *);
+
+void
+nat_t_init(void)
+{
+ nat_t_setup_hashes();
+}
+
+/* Generate the NAT-T capability marker hashes. Executed only once. */
+static int
+nat_t_setup_hashes(void)
+{
+ struct hash *hash;
+ int n = NUMNATTCAP;
+ int i;
+
+ /* The draft says to use MD5. */
+ hash = hash_get(HASH_MD5);
+ if (!hash) {
+ /* Should never happen. */
+ log_print("nat_t_setup_hashes: "
+ "could not find MD5 hash structure!");
+ return -1;
+ }
+
+ /* Populate isakmp_nat_t_cap with hashes. */
+ for (i = 0; i < n; i++) {
+ isakmp_nat_t_cap[i].hashsize = hash->hashsize;
+ isakmp_nat_t_cap[i].hash = (char *)malloc(hash->hashsize);
+ if (!isakmp_nat_t_cap[i].hash) {
+ log_error("nat_t_setup_hashes: malloc (%lu) failed",
+ (unsigned long)hash->hashsize);
+ goto errout;
+ }
+
+ hash->Init(hash->ctx);
+ hash->Update(hash->ctx,
+ (unsigned char *)isakmp_nat_t_cap[i].text,
+ strlen(isakmp_nat_t_cap[i].text));
+ hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx);
+
+ LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: "
+ "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text,
+ (unsigned long)hash->hashsize));
+ LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes",
+ isakmp_nat_t_cap[i].hash, hash->hashsize));
+ }
+
+ return 0;
+
+errout:
+ for (i = 0; i < n; i++)
+ if (isakmp_nat_t_cap[i].hash)
+ free(isakmp_nat_t_cap[i].hash);
+ return -1;
+}
+
+/* Add one NAT-T VENDOR payload. */
+static int
+nat_t_add_vendor_payload(struct message *msg, struct nat_t_cap *cap)
+{
+ size_t buflen = cap->hashsize + ISAKMP_GEN_SZ;
+ u_int8_t *buf;
+
+ if (disable_nat_t)
+ return 0;
+
+ buf = malloc(buflen);
+ if (!buf) {
+ log_error("nat_t_add_vendor_payload: malloc (%lu) failed",
+ (unsigned long)buflen);
+ return -1;
+ }
+
+ SET_ISAKMP_GEN_LENGTH(buf, buflen);
+ memcpy(buf + ISAKMP_VENDOR_ID_OFF, cap->hash, cap->hashsize);
+ if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) {
+ free(buf);
+ return -1;
+ }
+ return 0;
+}
+
+/* Add the NAT-T capability markers (VENDOR payloads). */
+int
+nat_t_add_vendor_payloads(struct message *msg)
+{
+ int i;
+
+ if (disable_nat_t)
+ return 0;
+
+ for (i = 0; i < NUMNATTCAP; i++)
+ if (nat_t_add_vendor_payload(msg, &isakmp_nat_t_cap[i]))
+ return -1;
+ return 0;
+}
+
+/*
+ * Check an incoming message for NAT-T capability markers.
+ */
+void
+nat_t_check_vendor_payload(struct message *msg, struct payload *p)
+{
+ u_int8_t *pbuf = p->p;
+ size_t vlen;
+ int i;
+
+ if (disable_nat_t)
+ return;
+
+ vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ;
+
+ for (i = 0; i < NUMNATTCAP; i++) {
+ if (vlen != isakmp_nat_t_cap[i].hashsize) {
+ LOG_DBG((LOG_EXCHANGE, 50, "nat_t_check_vendor_payload: "
+ "bad size %lu != %lu", (unsigned long)vlen,
+ (unsigned long)isakmp_nat_t_cap[i].hashsize));
+ continue;
+ }
+ if (memcmp(isakmp_nat_t_cap[i].hash, pbuf + ISAKMP_GEN_SZ,
+ vlen) == 0) {
+ /* This peer is NAT-T capable. */
+ msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER;
+ msg->exchange->flags |= isakmp_nat_t_cap[i].flags;
+ LOG_DBG((LOG_EXCHANGE, 10,
+ "nat_t_check_vendor_payload: "
+ "NAT-T capable peer detected"));
+ p->flags |= PL_MARK;
+ }
+ }
+
+ return;
+}
+
+/* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port). */
+static u_int8_t *
+nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa,
+ size_t *hashlen)
+{
+ struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data;
+ struct hash *hash;
+ u_int8_t *res;
+ in_port_t port;
+
+ hash = hash_get(ie->hash->type);
+ if (hash == NULL) {
+ log_print ("nat_t_generate_nat_d_hash: no hash");
+ return NULL;
+ }
+
+ *hashlen = hash->hashsize;
+
+ res = (u_int8_t *)malloc((unsigned long)*hashlen);
+ if (!res) {
+ log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed",
+ (unsigned long)*hashlen);
+ *hashlen = 0;
+ return NULL;
+ }
+
+ port = sockaddr_port(sa);
+ bzero(res, *hashlen);
+
+ hash->Init(hash->ctx);
+ hash->Update(hash->ctx, msg->exchange->cookies,
+ sizeof msg->exchange->cookies);
+ hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa));
+ hash->Update(hash->ctx, (unsigned char *)&port, sizeof port);
+ hash->Final(res, hash->ctx);
+ return res;
+}
+
+/* Add a NAT-D payload to our message. */
+static int
+nat_t_add_nat_d(struct message *msg, struct sockaddr *sa)
+{
+ int ret;
+ u_int8_t *hbuf, *buf;
+ size_t hbuflen, buflen;
+
+ hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
+ if (!hbuf) {
+ log_print("nat_t_add_nat_d: NAT-D hash gen failed");
+ return -1;
+ }
+
+ buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen;
+ buf = malloc(buflen);
+ if (!buf) {
+ log_error("nat_t_add_nat_d: malloc (%lu) failed",
+ (unsigned long)buflen);
+ free(hbuf);
+ return -1;
+ }
+
+ SET_ISAKMP_GEN_LENGTH(buf, buflen);
+ memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen);
+ free(hbuf);
+
+ if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_RFC)
+ ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf,
+ buflen, 1);
+ else if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_DRAFT)
+ ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT,
+ buf, buflen, 1);
+ else
+ ret = -1;
+
+ if (ret) {
+ free(buf);
+ return -1;
+ }
+ return 0;
+}
+
+/* We add two NAT-D payloads, one each for src and dst. */
+int
+nat_t_exchange_add_nat_d(struct message *msg)
+{
+ struct sockaddr *sa;
+
+ /* Remote address first. */
+ msg->transport->vtbl->get_dst(msg->transport, &sa);
+ if (nat_t_add_nat_d(msg, sa))
+ return -1;
+
+ msg->transport->vtbl->get_src(msg->transport, &sa);
+ if (nat_t_add_nat_d(msg, sa))
+ return -1;
+ return 0;
+}
+
+/* Generate and match a NAT-D hash against the NAT-D payload (pl.) data. */
+static int
+nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa)
+{
+ struct payload *p;
+ u_int8_t *hbuf;
+ size_t hbuflen;
+ int found = 0;
+
+ /*
+ * If there are no NAT-D payloads in the message, return "found"
+ * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()).
+ */
+ if ((p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT)) == NULL &&
+ (p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D)) == NULL)
+ return 1;
+
+ hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
+ if (!hbuf)
+ return 0;
+
+ while (p) {
+ if (GET_ISAKMP_GEN_LENGTH (p->p) !=
+ hbuflen + ISAKMP_NAT_D_DATA_OFF)
+ continue;
+
+ if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) {
+ found++;
+ break;
+ }
+ p = TAILQ_NEXT(p, link);
+ }
+ free(hbuf);
+ return found;
+}
+
+/*
+ * Check if we need to activate NAT-T, and if we need to send keepalive
+ * messages to the other side, i.e if we are a nat:ed peer.
+ */
+int
+nat_t_exchange_check_nat_d(struct message *msg)
+{
+ struct sockaddr *sa;
+ int outgoing_path_is_clear, incoming_path_is_clear;
+
+ /* Assume trouble, i.e NAT-boxes in our path. */
+ outgoing_path_is_clear = incoming_path_is_clear = 0;
+
+ msg->transport->vtbl->get_src(msg->transport, &sa);
+ if (nat_t_match_nat_d_payload(msg, sa))
+ outgoing_path_is_clear = 1;
+
+ msg->transport->vtbl->get_dst(msg->transport, &sa);
+ if (nat_t_match_nat_d_payload(msg, sa))
+ incoming_path_is_clear = 1;
+
+ if (outgoing_path_is_clear && incoming_path_is_clear) {
+ LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: "
+ "no NAT"));
+ return 0; /* No NAT-T required. */
+ }
+
+ /* NAT-T handling required. */
+ msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
+
+ if (!outgoing_path_is_clear) {
+ msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE;
+ LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: "
+ "NAT detected, we're behind it"));
+ } else
+ LOG_DBG ((LOG_EXCHANGE, 10,
+ "nat_t_exchange_check_nat_d: NAT detected"));
+ return 1;
+}
+
+static void
+nat_t_send_keepalive(void *v_arg)
+{
+ struct sa *sa = (struct sa *)v_arg;
+ struct transport *t;
+ struct timeval now;
+ int interval;
+
+ /* Send the keepalive message. */
+ t = ((struct virtual_transport *)sa->transport)->encap;
+ t->vtbl->send_message(NULL, t);
+
+ /* Set new timer. */
+ interval = conf_get_num("General", "NAT-T-Keepalive", 0);
+ if (interval < 1)
+ interval = NAT_T_KEEPALIVE_INTERVAL;
+ gettimeofday(&now, 0);
+ now.tv_sec += interval;
+
+ sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
+ nat_t_send_keepalive, v_arg, &now);
+ if (!sa->nat_t_keepalive)
+ log_print("nat_t_send_keepalive: "
+ "timer_add_event() failed, will send no more keepalives");
+}
+
+void
+nat_t_setup_keepalive(struct sa *sa)
+{
+ struct sockaddr *src;
+ struct timeval now;
+
+ if (sa->initiator)
+ sa->transport->vtbl->get_src(sa->transport, &src);
+ else
+ sa->transport->vtbl->get_dst(sa->transport, &src);
+
+ if (!virtual_listen_lookup(src))
+ return;
+
+ gettimeofday(&now, 0);
+ now.tv_sec += NAT_T_KEEPALIVE_INTERVAL;
+
+ sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
+ nat_t_send_keepalive, sa, &now);
+ if (!sa->nat_t_keepalive)
+ log_print("nat_t_setup_keepalive: "
+ "timer_add_event() failed, will not send keepalives");
+
+ LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: "
+ "added event for phase 1 SA %p", sa));
+}
diff --git a/keyexchange/isakmpd-20041012/nat_traversal.h b/keyexchange/isakmpd-20041012/nat_traversal.h
new file mode 100644
index 0000000..843d43b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/nat_traversal.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: nat_traversal.h,v 1.4 2005/07/25 15:03:47 hshoexer Exp $ */
+
+/*
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _NAT_TRAVERSAL_H_
+#define _NAT_TRAVERSAL_H_
+
+#define VID_DRAFT_V2 0
+#define VID_DRAFT_V2_N 1
+#define VID_DRAFT_V3 2
+#define VID_RFC3947 3
+
+struct nat_t_cap {
+ int id;
+ u_int32_t flags;
+ const char *text;
+ char *hash;
+ size_t hashsize;
+};
+
+/*
+ * Set if -T is given on the command line to disable NAT-T support.
+ */
+extern int disable_nat_t;
+
+void nat_t_init(void);
+int nat_t_add_vendor_payloads(struct message *);
+void nat_t_check_vendor_payload(struct message *, struct payload *);
+int nat_t_exchange_add_nat_d(struct message *);
+int nat_t_exchange_check_nat_d(struct message *);
+void nat_t_setup_keepalive(struct sa *);
+
+#endif /* _NAT_TRAVERSAL_H_ */
diff --git a/keyexchange/isakmpd-20041012/pf_key_v2.c b/keyexchange/isakmpd-20041012/pf_key_v2.c
new file mode 100644
index 0000000..d8cbc35
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/pf_key_v2.c
@@ -0,0 +1,4442 @@
+/* $OpenBSD: pf_key_v2.c,v 1.150 2004/09/17 13:53:08 ho Exp $ */
+/* $EOM: pf_key_v2.c,v 1.79 2000/12/12 00:33:19 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include "sysdep.h"
+
+#if !defined (LINUX_IPSEC)
+#include <net/pfkeyv2.h>
+#endif
+#include <netinet/in.h>
+#ifdef SADB_X_EXT_FLOW_TYPE
+#include <sys/mbuf.h>
+#include <netinet/ip_ipsp.h>
+#endif
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <bitstring.h>
+
+#include "cert.h"
+#include "conf.h"
+#include "exchange.h"
+#include "ipsec.h"
+#include "ipsec_num.h"
+#include "key.h"
+#include "log.h"
+#include "pf_key_v2.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+
+#if defined (USE_KEYNOTE)
+#include "policy.h"
+#endif
+
+#if defined (USE_NAT_TRAVERSAL)
+#include "udp_encap.h"
+#endif
+
+#define IN6_IS_ADDR_FULL(a) \
+ ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffff) && \
+ (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffff) && \
+ (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffff) && \
+ (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffff))
+
+#define ADDRESS_MAX sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"
+
+/*
+ * PF_KEY v2 always work with 64-bit entities and aligns on 64-bit boundaries.
+ */
+#define PF_KEY_V2_CHUNK 8
+#define PF_KEY_V2_ROUND(x) \
+ (((x) + PF_KEY_V2_CHUNK - 1) & ~(PF_KEY_V2_CHUNK - 1))
+
+/* How many microseconds we will wait for a reply from the PF_KEY socket. */
+#define PF_KEY_REPLY_TIMEOUT 1000
+
+struct pf_key_v2_node {
+ TAILQ_ENTRY(pf_key_v2_node) link;
+ void *seg;
+ size_t sz;
+ int cnt;
+ u_int16_t type;
+ u_int8_t flags;
+};
+
+TAILQ_HEAD(pf_key_v2_msg, pf_key_v2_node);
+
+#define PF_KEY_V2_NODE_MALLOCED 1
+#define PF_KEY_V2_NODE_MARK 2
+
+/* Used to derive "unique" connection identifiers. */
+int connection_seq = 0;
+
+#ifdef KAME
+/*
+ * KAME requires the sadb_msg_seq of an UPDATE be the same of that of the
+ * GETSPI creating the larval SA.
+ */
+struct pf_key_v2_sa_seq {
+ TAILQ_ENTRY(pf_key_v2_sa_seq) link;
+ u_int8_t *spi;
+ size_t sz;
+ u_int8_t proto;
+ struct sockaddr *dst;
+ int dstlen;
+ u_int32_t seq;
+};
+
+TAILQ_HEAD(, pf_key_v2_sa_seq) pf_key_v2_sa_seq_map;
+#endif
+
+#ifndef KAME
+static u_int8_t *pf_key_v2_convert_id(u_int8_t *, int, size_t *, int *);
+#endif
+static struct pf_key_v2_msg *pf_key_v2_call(struct pf_key_v2_msg *);
+static struct pf_key_v2_node *pf_key_v2_find_ext(struct pf_key_v2_msg *,
+ u_int16_t);
+static void pf_key_v2_notify(struct pf_key_v2_msg *);
+static struct pf_key_v2_msg *pf_key_v2_read(u_int32_t);
+static u_int32_t pf_key_v2_seq(void);
+static u_int32_t pf_key_v2_write(struct pf_key_v2_msg *);
+static int pf_key_v2_remove_conf(char *);
+static int pf_key_v2_conf_refhandle(int, char *);
+
+#ifdef SADB_X_ASKPOLICY
+static int pf_key_v2_conf_refinc(int, char *);
+#endif
+
+/* The socket to use for PF_KEY interactions. */
+int pf_key_v2_socket;
+
+#ifdef KAME
+static int
+pf_key_v2_register_sa_seq(u_int8_t *spi, size_t sz, u_int8_t proto,
+ struct sockaddr *dst, int dstlen, u_int32_t seq)
+{
+ struct pf_key_v2_sa_seq *node = 0;
+
+ node = malloc(sizeof *node);
+ if (!node)
+ goto cleanup;
+ memset(node, '0', sizeof *node);
+ node->spi = malloc(sz);
+ if (!node->spi)
+ goto cleanup;
+ node->dst = malloc(sysdep_sa_len(dst));
+ if (!node->dst)
+ goto cleanup;
+ memcpy(node->dst, dst, sysdep_sa_len(dst));
+ node->dstlen = sysdep_sa_len(dst);
+ memcpy(node->spi, spi, sz);
+ node->sz = sz;
+ node->proto = proto;
+ node->seq = seq;
+ TAILQ_INSERT_TAIL(&pf_key_v2_sa_seq_map, node, link);
+ return 1;
+
+cleanup:
+ if (node->dst)
+ free(node->dst);
+ if (node)
+ free(node);
+ return 0;
+}
+
+static u_int32_t
+pf_key_v2_seq_by_sa(u_int8_t *spi, size_t sz, u_int8_t proto,
+ struct sockaddr *dst, int dstlen)
+{
+ struct pf_key_v2_sa_seq *node;
+
+ for (node = TAILQ_FIRST(&pf_key_v2_sa_seq_map); node;
+ node = TAILQ_NEXT(node, link))
+ if (node->proto == proto &&
+ node->sz == sz && memcmp(node->spi, spi, sz) == 0 &&
+ node->dstlen == sysdep_sa_len(dst) &&
+ memcmp(node->dst, dst, sysdep_sa_len(dst)) == 0)
+ return node->seq;
+ return 0;
+}
+#endif
+
+static struct pf_key_v2_msg *
+pf_key_v2_msg_new(struct sadb_msg *msg, int flags)
+{
+ struct pf_key_v2_node *node = 0;
+ struct pf_key_v2_msg *ret;
+
+ node = malloc(sizeof *node);
+ if (!node)
+ goto cleanup;
+ ret = malloc(sizeof *ret);
+ if (!ret)
+ goto cleanup;
+ TAILQ_INIT(ret);
+ node->seg = msg;
+ node->sz = sizeof *msg;
+ node->type = 0;
+ node->cnt = 1;
+ node->flags = flags;
+ TAILQ_INSERT_HEAD(ret, node, link);
+ return ret;
+
+cleanup:
+ if (node)
+ free(node);
+ return 0;
+}
+
+/* Add a SZ sized segment SEG to the PF_KEY message MSG. */
+static int
+pf_key_v2_msg_add(struct pf_key_v2_msg *msg, struct sadb_ext *ext, int flags)
+{
+ struct pf_key_v2_node *node;
+
+ node = malloc(sizeof *node);
+ if (!node)
+ return -1;
+ node->seg = ext;
+ node->sz = ext->sadb_ext_len * PF_KEY_V2_CHUNK;
+ node->type = ext->sadb_ext_type;
+ node->flags = flags;
+ TAILQ_FIRST(msg)->cnt++;
+ TAILQ_INSERT_TAIL(msg, node, link);
+ return 0;
+}
+
+/* Deallocate the PF_KEY message MSG. */
+static void
+pf_key_v2_msg_free(struct pf_key_v2_msg *msg)
+{
+ struct pf_key_v2_node *np;
+
+ np = TAILQ_FIRST(msg);
+ while (np) {
+ TAILQ_REMOVE(msg, np, link);
+ if (np->flags & PF_KEY_V2_NODE_MALLOCED)
+ free(np->seg);
+ free(np);
+ np = TAILQ_FIRST(msg);
+ }
+ free(msg);
+}
+
+/* Just return a new sequence number. */
+static u_int32_t
+pf_key_v2_seq(void)
+{
+ static u_int32_t seq = 0;
+
+ return ++seq;
+}
+
+/*
+ * Read a PF_KEY packet with SEQ as the sequence number, looping if necessary.
+ * If SEQ is zero just read the first message we see, otherwise we queue
+ * messages up until both the PID and the sequence number match.
+ */
+static struct pf_key_v2_msg *
+pf_key_v2_read(u_int32_t seq)
+{
+ ssize_t n;
+ u_int8_t *buf = 0;
+ struct pf_key_v2_msg *ret = 0;
+ struct sadb_msg *msg;
+ struct sadb_msg hdr;
+ struct sadb_ext *ext;
+ struct timeval tv;
+ fd_set *fds;
+
+ while (1) {
+ /*
+ * If this is a read of a reply we should actually expect the
+ * reply to get lost as PF_KEY is an unreliable service per
+ * the specs. Currently we do this by setting a short timeout,
+ * and if it is not readable in that time, we fail the read.
+ */
+ if (seq) {
+ fds = calloc(howmany(pf_key_v2_socket + 1, NFDBITS),
+ sizeof(fd_mask));
+ if (!fds) {
+ log_error("pf_key_v2_read: "
+ "calloc (%lu, %lu) failed",
+ (unsigned long) howmany(pf_key_v2_socket + 1,
+ NFDBITS),
+ (unsigned long) sizeof(fd_mask));
+ goto cleanup;
+ }
+ FD_SET(pf_key_v2_socket, fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = PF_KEY_REPLY_TIMEOUT;
+ n = select(pf_key_v2_socket + 1, fds, 0, 0, &tv);
+ free(fds);
+ if (n == -1) {
+ log_error("pf_key_v2_read: "
+ "select (%d, fds, 0, 0, &tv) failed",
+ pf_key_v2_socket + 1);
+ goto cleanup;
+ }
+ if (!n) {
+ log_print("pf_key_v2_read: "
+ "no reply from PF_KEY");
+ goto cleanup;
+ }
+ }
+ n = recv(pf_key_v2_socket, &hdr, sizeof hdr, MSG_PEEK);
+ if (n == -1) {
+ log_error("pf_key_v2_read: recv (%d, ...) failed",
+ pf_key_v2_socket);
+ goto cleanup;
+ }
+ if (n != sizeof hdr) {
+ log_error("pf_key_v2_read: recv (%d, ...) "
+ "returned short packet (%lu bytes)",
+ pf_key_v2_socket, (unsigned long) n);
+ goto cleanup;
+ }
+ n = hdr.sadb_msg_len * PF_KEY_V2_CHUNK;
+ buf = malloc(n);
+ if (!buf) {
+ log_error("pf_key_v2_read: malloc (%lu) failed",
+ (unsigned long) n);
+ goto cleanup;
+ }
+ n = read(pf_key_v2_socket, buf, n);
+ if (n == -1) {
+ log_error("pf_key_v2_read: read (%d, ...) failed",
+ pf_key_v2_socket);
+ goto cleanup;
+ }
+ if (n != hdr.sadb_msg_len * PF_KEY_V2_CHUNK) {
+ log_print("pf_key_v2_read: read (%d, ...) "
+ "returned short packet (%lu bytes)",
+ pf_key_v2_socket, (unsigned long) n);
+ goto cleanup;
+ }
+ LOG_DBG_BUF((LOG_SYSDEP, 80, "pf_key_v2_read: msg", buf, n));
+
+ /* We drop all messages that is not what we expect. */
+ msg = (struct sadb_msg *) buf;
+ if (msg->sadb_msg_version != PF_KEY_V2 ||
+ (msg->sadb_msg_pid != 0 &&
+ msg->sadb_msg_pid != (u_int32_t) getpid())) {
+ if (seq) {
+ free(buf);
+ buf = 0;
+ continue;
+ } else {
+ LOG_DBG((LOG_SYSDEP, 90, "pf_key_v2_read:"
+ "bad version (%d) or PID (%d, mine is "
+ "%ld), ignored", msg->sadb_msg_version,
+ msg->sadb_msg_pid, (long) getpid()));
+ goto cleanup;
+ }
+ }
+ /* Parse the message. */
+ ret = pf_key_v2_msg_new(msg, PF_KEY_V2_NODE_MALLOCED);
+ if (!ret)
+ goto cleanup;
+ buf = 0;
+ for (ext = (struct sadb_ext *) (msg + 1);
+ (u_int8_t *) ext - (u_int8_t *) msg <
+ msg->sadb_msg_len * PF_KEY_V2_CHUNK;
+ ext = (struct sadb_ext *) ((u_int8_t *) ext +
+ ext->sadb_ext_len * PF_KEY_V2_CHUNK))
+ pf_key_v2_msg_add(ret, ext, 0);
+
+ /*
+ * If the message is not the one we are waiting for, queue it
+ * up.
+ */
+ if (seq && (msg->sadb_msg_pid != (u_int32_t) getpid() ||
+ msg->sadb_msg_seq != seq)) {
+ gettimeofday(&tv, 0);
+ timer_add_event("pf_key_v2_notify",
+ (void (*) (void *)) pf_key_v2_notify, ret, &tv);
+ ret = 0;
+ continue;
+ }
+ return ret;
+ }
+
+cleanup:
+ if (buf)
+ free(buf);
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return 0;
+}
+
+/* Write the message in PMSG to the PF_KEY socket. */
+u_int32_t
+pf_key_v2_write(struct pf_key_v2_msg *pmsg)
+{
+ struct iovec *iov = 0;
+ ssize_t n;
+ size_t len;
+ int i, cnt = TAILQ_FIRST(pmsg)->cnt;
+ char header[80];
+ struct sadb_msg *msg = TAILQ_FIRST(pmsg)->seg;
+ struct pf_key_v2_node *np = TAILQ_FIRST(pmsg);
+
+ iov = (struct iovec *) malloc(cnt * sizeof *iov);
+ if (!iov) {
+ log_error("pf_key_v2_write: malloc (%lu) failed",
+ cnt * (unsigned long) sizeof *iov);
+ return 0;
+ }
+ msg->sadb_msg_version = PF_KEY_V2;
+ msg->sadb_msg_errno = 0;
+ msg->sadb_msg_reserved = 0;
+ msg->sadb_msg_pid = getpid();
+ if (!msg->sadb_msg_seq)
+ msg->sadb_msg_seq = pf_key_v2_seq();
+
+ /* Compute the iovec segments as well as the message length. */
+ len = 0;
+ for (i = 0; i < cnt; i++) {
+ iov[i].iov_base = np->seg;
+ len += iov[i].iov_len = np->sz;
+
+ /*
+ * XXX One can envision setting specific extension fields, like
+ * *_reserved ones here. For now we require them to be set by the
+ * caller.
+ */
+
+ np = TAILQ_NEXT(np, link);
+ }
+ msg->sadb_msg_len = len / PF_KEY_V2_CHUNK;
+
+ for (i = 0; i < cnt; i++) {
+ snprintf(header, sizeof header, "pf_key_v2_write: iov[%d]", i);
+ LOG_DBG_BUF((LOG_SYSDEP, 80, header,
+ (u_int8_t *) iov[i].iov_base, iov[i].iov_len));
+ }
+
+ n = writev(pf_key_v2_socket, iov, cnt);
+ if (n == -1) {
+ log_error("pf_key_v2_write: writev (%d, %p, %d) failed",
+ pf_key_v2_socket, iov, cnt);
+ goto cleanup;
+ }
+ if ((size_t) n != len) {
+ log_error("pf_key_v2_write: "
+ "writev (%d, ...) returned prematurely (%lu)",
+ pf_key_v2_socket, (unsigned long) n);
+ goto cleanup;
+ }
+ free(iov);
+ return msg->sadb_msg_seq;
+
+cleanup:
+ if (iov)
+ free(iov);
+ return 0;
+}
+
+/*
+ * Do a PF_KEY "call", i.e. write a message MSG, read the reply and return
+ * it to the caller.
+ */
+static struct pf_key_v2_msg *
+pf_key_v2_call(struct pf_key_v2_msg *msg)
+{
+ u_int32_t seq;
+
+ seq = pf_key_v2_write(msg);
+ if (!seq)
+ return 0;
+ return pf_key_v2_read(seq);
+}
+
+/* Find the TYPE extension in MSG. Return zero if none found. */
+static struct pf_key_v2_node *
+pf_key_v2_find_ext(struct pf_key_v2_msg *msg, u_int16_t type)
+{
+ struct pf_key_v2_node *ext;
+
+ for (ext = TAILQ_NEXT(TAILQ_FIRST(msg), link); ext;
+ ext = TAILQ_NEXT(ext, link))
+ if (ext->type == type)
+ return ext;
+ return 0;
+}
+
+/*
+ * Open the PF_KEYv2 sockets and return the descriptor used for notifies.
+ * Return -1 for failure and -2 if no notifies will show up.
+ */
+int
+pf_key_v2_open(void)
+{
+ int fd = -1, err;
+ struct sadb_msg msg;
+ struct pf_key_v2_msg *regmsg = 0, *ret = 0;
+
+ /* Open the socket we use to speak to IPsec. */
+ pf_key_v2_socket = -1;
+ fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
+ if (fd == -1) {
+ log_error("pf_key_v2_open: "
+ "socket (PF_KEY, SOCK_RAW, PF_KEY_V2) failed");
+ goto cleanup;
+ }
+ pf_key_v2_socket = fd;
+
+ /* Register it to get ESP and AH acquires from the kernel. */
+ msg.sadb_msg_seq = 0;
+ msg.sadb_msg_type = SADB_REGISTER;
+ msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ regmsg = pf_key_v2_msg_new(&msg, 0);
+ if (!regmsg)
+ goto cleanup;
+ ret = pf_key_v2_call(regmsg);
+ pf_key_v2_msg_free(regmsg);
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (err) {
+ log_print("pf_key_v2_open: REGISTER: %s", strerror(err));
+ goto cleanup;
+ }
+ /* XXX Register the accepted transforms. */
+
+ pf_key_v2_msg_free(ret);
+ ret = 0;
+
+ msg.sadb_msg_seq = 0;
+ msg.sadb_msg_type = SADB_REGISTER;
+ msg.sadb_msg_satype = SADB_SATYPE_AH;
+ regmsg = pf_key_v2_msg_new(&msg, 0);
+ if (!regmsg)
+ goto cleanup;
+ ret = pf_key_v2_call(regmsg);
+ pf_key_v2_msg_free(regmsg);
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (err) {
+ log_print("pf_key_v2_open: REGISTER: %s", strerror(err));
+ goto cleanup;
+ }
+ /* XXX Register the accepted transforms. */
+
+ pf_key_v2_msg_free(ret);
+ ret = 0;
+
+#ifdef SADB_X_SATYPE_IPCOMP
+ msg.sadb_msg_seq = 0;
+ msg.sadb_msg_type = SADB_REGISTER;
+ msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
+ regmsg = pf_key_v2_msg_new(&msg, 0);
+ if (!regmsg)
+ goto cleanup;
+ ret = pf_key_v2_call(regmsg);
+ pf_key_v2_msg_free(regmsg);
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (err) {
+ log_print("pf_key_v2_open: REGISTER: %s", strerror(err));
+ goto cleanup;
+ }
+ /* XXX Register the accepted transforms. */
+
+ pf_key_v2_msg_free(ret);
+#endif /* SADB_X_SATYPE_IPCOMP */
+
+#ifdef KAME
+ TAILQ_INIT(&pf_key_v2_sa_seq_map);
+#endif
+
+ return fd;
+
+cleanup:
+ if (pf_key_v2_socket != -1) {
+ close(pf_key_v2_socket);
+ pf_key_v2_socket = -1;
+ }
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return -1;
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+pf_key_v2_get_spi(size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ struct sadb_msg msg;
+ struct sadb_sa *sa;
+ struct sadb_address *addr = 0;
+ struct sadb_spirange spirange;
+ struct pf_key_v2_msg *getspi = 0, *ret = 0;
+ struct pf_key_v2_node *ext;
+ u_int8_t *spi = 0;
+ int len, err;
+#ifdef KAME
+ struct sadb_x_sa2 ssa2;
+#endif
+
+ msg.sadb_msg_type = SADB_GETSPI;
+ switch (proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ break;
+ case IPSEC_PROTO_IPSEC_AH:
+ msg.sadb_msg_satype = SADB_SATYPE_AH;
+ break;
+#ifdef SADB_X_SATYPE_IPCOMP
+ case IPSEC_PROTO_IPCOMP:
+ msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
+ break;
+#endif
+ default:
+ log_print("pf_key_v2_get_spi: invalid proto %d", proto);
+ goto cleanup;
+ }
+
+ /* Set the sequence number from the ACQUIRE message. */
+ msg.sadb_msg_seq = seq;
+ getspi = pf_key_v2_msg_new(&msg, 0);
+ if (!getspi)
+ goto cleanup;
+
+#ifdef KAME
+ memset(&ssa2, 0, sizeof ssa2);
+ ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;
+ ssa2.sadb_x_sa2_mode = 0;
+ if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&ssa2, 0) == -1)
+ goto cleanup;
+#endif
+
+ /* Setup the ADDRESS extensions. */
+ len =
+ sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(src));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, src, sysdep_sa_len(src));
+ switch (((struct sockaddr *) (addr + 1))->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
+ break;
+ }
+ if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ len =
+ sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, dst, sysdep_sa_len(dst));
+ switch (((struct sockaddr *) (addr + 1))->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
+ break;
+ }
+ if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ /* Setup the SPIRANGE extension. */
+ spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ spirange.sadb_spirange_len = sizeof spirange / PF_KEY_V2_CHUNK;
+ if (proto == IPSEC_PROTO_IPCOMP) {
+ spirange.sadb_spirange_min = CPI_RESERVED_MAX + 1;
+ spirange.sadb_spirange_max = CPI_PRIVATE_MIN - 1;
+ } else {
+ spirange.sadb_spirange_min = IPSEC_SPI_LOW;
+ spirange.sadb_spirange_max = 0xffffffff;
+ }
+ spirange.sadb_spirange_reserved = 0;
+ if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&spirange, 0) == -1)
+ goto cleanup;
+
+ ret = pf_key_v2_call(getspi);
+ pf_key_v2_msg_free(getspi);
+ getspi = 0;
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (err) {
+ log_print("pf_key_v2_get_spi: GETSPI: %s", strerror(err));
+ goto cleanup;
+ }
+ ext = pf_key_v2_find_ext(ret, SADB_EXT_SA);
+ if (!ext) {
+ log_print("pf_key_v2_get_spi: no SA extension found");
+ goto cleanup;
+ }
+ sa = ext->seg;
+
+ /* IPCOMP CPIs are only 16 bits long. */
+ *sz = (proto == IPSEC_PROTO_IPCOMP) ? sizeof(u_int16_t)
+ : sizeof sa->sadb_sa_spi;
+ spi = malloc(*sz);
+ if (!spi)
+ goto cleanup;
+ /* XXX This is ugly. */
+ if (proto == IPSEC_PROTO_IPCOMP) {
+ u_int32_t tspi = ntohl(sa->sadb_sa_spi);
+ *(u_int16_t *) spi = htons((u_int16_t) tspi);
+ } else
+ memcpy(spi, &sa->sadb_sa_spi, *sz);
+
+#ifdef KAME
+ if (!pf_key_v2_register_sa_seq(spi, *sz, proto, dst,
+ sysdep_sa_len(dst),
+ ((struct sadb_msg *) (TAILQ_FIRST(ret)->seg))->sadb_msg_seq))
+ goto cleanup;
+#endif
+ pf_key_v2_msg_free(ret);
+
+ LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_spi: spi", spi, *sz));
+ return spi;
+
+cleanup:
+ if (spi)
+ free(spi);
+ if (addr)
+ free(addr);
+ if (getspi)
+ pf_key_v2_msg_free(getspi);
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return 0;
+}
+
+/* Fetch SA information from the kernel. XXX OpenBSD only? */
+struct sa_kinfo *
+pf_key_v2_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
+ struct sockaddr *dst)
+{
+ struct sadb_msg msg;
+ struct sadb_sa *ssa;
+ struct sadb_address *addr = 0;
+ struct sockaddr *sa;
+ struct sadb_lifetime *life;
+ struct pf_key_v2_msg *gettdb = 0, *ret = 0;
+ struct pf_key_v2_node *ext;
+ static struct sa_kinfo ksa;
+#if defined (SADB_X_EXT_UDPENCAP)
+ struct sadb_x_udpencap *udpencap;
+#endif
+ int len, err;
+
+ if (spi_sz != sizeof (ssa->sadb_sa_spi))
+ return 0;
+
+ msg.sadb_msg_type = SADB_GET;
+ switch (proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ break;
+ case IPSEC_PROTO_IPSEC_AH:
+ msg.sadb_msg_satype = SADB_SATYPE_AH;
+ break;
+#ifdef SADB_X_SATYPE_IPCOMP
+ case IPSEC_PROTO_IPCOMP:
+ msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
+ break;
+#endif
+ default:
+ log_print("pf_key_v2_get_kernel_sa: invalid proto %d", proto);
+ goto cleanup;
+ }
+
+ gettdb = pf_key_v2_msg_new(&msg, 0);
+ if (!gettdb)
+ goto cleanup;
+
+ /* SPI */
+ ssa = (struct sadb_sa *)calloc(1, sizeof *ssa);
+ if (!ssa) {
+ log_print("pf_key_v2_get_kernel_sa: calloc(1, %lu) failed",
+ (unsigned long)sizeof *ssa);
+ goto cleanup;
+ }
+
+ ssa->sadb_sa_exttype = SADB_EXT_SA;
+ ssa->sadb_sa_len = sizeof *ssa / PF_KEY_V2_CHUNK;
+ memcpy(&ssa->sadb_sa_spi, spi, sizeof ssa->sadb_sa_spi);
+ ssa->sadb_sa_state = SADB_SASTATE_MATURE;
+ if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)ssa,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ ssa = 0;
+
+ /* XXX KAME SADB_X_EXT_xyz here? */
+
+ /* Address */
+ len =
+ sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, dst, sysdep_sa_len(dst));
+ switch (((struct sockaddr *) (addr + 1))->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
+ break;
+ }
+ if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ ret = pf_key_v2_call(gettdb);
+ pf_key_v2_msg_free(gettdb);
+ gettdb = 0;
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (err) {
+ log_print("pf_key_v2_get_kernel_sa: SADB_GET: %s",
+ strerror(err));
+ goto cleanup;
+ }
+
+ /* Extract the data. */
+ memset(&ksa, 0, sizeof ksa);
+
+ ext = pf_key_v2_find_ext(ret, SADB_EXT_SA);
+ if (!ext)
+ goto cleanup;
+
+ ssa = (struct sadb_sa *)ext;
+ ksa.spi = ssa->sadb_sa_spi;
+ ksa.wnd = ssa->sadb_sa_replay;
+ ksa.flags = ssa->sadb_sa_flags;
+
+ ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_CURRENT);
+ if (ext) {
+ life = (struct sadb_lifetime *)ext->seg;
+ ksa.cur_allocations = life->sadb_lifetime_allocations;
+ ksa.cur_bytes = life->sadb_lifetime_bytes;
+ ksa.first_use = life->sadb_lifetime_usetime;
+ ksa.established = life->sadb_lifetime_addtime;
+ }
+
+ ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_SOFT);
+ if (ext) {
+ life = (struct sadb_lifetime *)ext->seg;
+ ksa.soft_allocations = life->sadb_lifetime_allocations;
+ ksa.soft_bytes = life->sadb_lifetime_bytes;
+ ksa.soft_timeout = life->sadb_lifetime_addtime;
+ ksa.soft_first_use = life->sadb_lifetime_usetime;
+ }
+
+ ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_HARD);
+ if (ext) {
+ life = (struct sadb_lifetime *)ext->seg;
+ ksa.exp_allocations = life->sadb_lifetime_allocations;
+ ksa.exp_bytes = life->sadb_lifetime_bytes;
+ ksa.exp_timeout = life->sadb_lifetime_addtime;
+ ksa.exp_first_use = life->sadb_lifetime_usetime;
+ }
+
+#if defined (SADB_X_EXT_LIFETIME_LASTUSE)
+ ext = pf_key_v2_find_ext(ret, SADB_X_EXT_LIFETIME_LASTUSE);
+ if (ext) {
+ life = (struct sadb_lifetime *)ext->seg;
+ ksa.last_used = life->sadb_lifetime_usetime;
+ }
+#endif
+
+ ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_SRC);
+ if (ext) {
+ sa = (struct sockaddr *)ext->seg;
+ memcpy(&ksa.src, sa,
+ sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
+ sizeof(struct sockaddr_in6));
+ }
+
+ ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_DST);
+ if (ext) {
+ sa = (struct sockaddr *)ext->seg;
+ memcpy(&ksa.dst, sa,
+ sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
+ sizeof(struct sockaddr_in6));
+ }
+
+ ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_PROXY);
+ if (ext) {
+ sa = (struct sockaddr *)ext->seg;
+ memcpy(sa, &ksa.proxy,
+ sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
+ sizeof(struct sockaddr_in6));
+ }
+
+#if defined (SADB_X_EXT_UDPENCAP)
+ ext = pf_key_v2_find_ext(ret, SADB_X_EXT_UDPENCAP);
+ if (ext) {
+ udpencap = (struct sadb_x_udpencap *)ext->seg;
+ ksa.udpencap_port = udpencap->sadb_x_udpencap_port;
+ }
+#endif
+
+ pf_key_v2_msg_free(ret);
+
+ LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_kernel_sa: spi", spi,
+ spi_sz));
+
+ return &ksa;
+
+ cleanup:
+ if (addr)
+ free (addr);
+ if (gettdb)
+ pf_key_v2_msg_free(gettdb);
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return 0;
+}
+
+static void
+pf_key_v2_setup_sockaddr(void *res, struct sockaddr *src,
+ struct sockaddr *dst, in_port_t port, int ingress)
+{
+ struct sockaddr_in *ip4_sa;
+ struct sockaddr_in6 *ip6_sa;
+ u_int8_t *p;
+
+ switch (src->sa_family) {
+ case AF_INET:
+ ip4_sa = (struct sockaddr_in *) res;
+ ip4_sa->sin_family = AF_INET;
+#ifndef USE_OLD_SOCKADDR
+ ip4_sa->sin_len = sizeof *ip4_sa;
+#endif
+ ip4_sa->sin_port = port;
+ if (dst)
+ p = (u_int8_t *) (ingress ?
+ &((struct sockaddr_in *)src)->sin_addr.s_addr :
+ &((struct sockaddr_in *)dst)->sin_addr.s_addr);
+ else
+ p = (u_int8_t *)&((struct sockaddr_in *)src)->sin_addr.s_addr;
+ ip4_sa->sin_addr.s_addr = *((in_addr_t *) p);
+ break;
+
+ case AF_INET6:
+ ip6_sa = (struct sockaddr_in6 *) res;
+ ip6_sa->sin6_family = AF_INET6;
+#ifndef USE_OLD_SOCKADDR
+ ip6_sa->sin6_len = sizeof *ip6_sa;
+#endif
+ ip6_sa->sin6_port = port;
+ if (dst)
+ p = (u_int8_t *) (ingress ?
+ &((struct sockaddr_in6 *)src)->sin6_addr.s6_addr :
+ &((struct sockaddr_in6 *)dst)->sin6_addr.s6_addr);
+ else
+ p = (u_int8_t *)&((struct sockaddr_in6 *)src)->sin6_addr.s6_addr;
+ memcpy(ip6_sa->sin6_addr.s6_addr, p, sizeof(struct in6_addr));
+ break;
+
+ default:
+ log_print("pf_key_v2_setup_sockaddr: unknown family %d\n",
+ src->sa_family);
+ break;
+ }
+}
+
+/*
+ * Store/update a PF_KEY_V2 security association with full information from the
+ * IKE SA and PROTO into the kernel. INCOMING is set if we are setting the
+ * parameters for the incoming SA, and cleared otherwise.
+ */
+int
+pf_key_v2_set_spi(struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ struct sadb_msg msg;
+ struct sadb_sa ssa;
+ struct sadb_lifetime *life = 0;
+ struct sadb_address *addr = 0;
+ struct sadb_key *key = 0;
+ struct sadb_ident *sid = 0;
+ struct sockaddr *src, *dst;
+ struct pf_key_v2_msg *update = 0, *ret = 0;
+ struct ipsec_proto *iproto = proto->data;
+ size_t len;
+ int keylen, hashlen, err;
+#ifndef KAME
+ u_int8_t *pp;
+ int idtype;
+#else /* KAME */
+ struct sadb_x_sa2 ssa2;
+#endif
+#if defined (SADB_X_CREDTYPE_NONE) || defined (SADB_X_AUTHTYPE_NONE)
+ struct ipsec_sa *isa = sa->data;
+ struct sadb_x_cred *cred;
+ struct sadb_protocol flowtype, tprotocol;
+#endif
+#if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP)
+ struct sadb_x_udpencap udpencap;
+#elif defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_NAT_T_TYPE)
+ struct sadb_x_nat_t_type nat_t_type;
+ struct sadb_x_nat_t_port nat_t_sport;
+ struct sadb_x_nat_t_port nat_t_dport;
+#endif
+#ifdef USE_DEBUG
+ char *addr_str;
+#endif
+
+ msg.sadb_msg_type = incoming ? SADB_UPDATE : SADB_ADD;
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ keylen = ipsec_esp_enckeylength(proto);
+ hashlen = ipsec_esp_authkeylength(proto);
+
+ switch (proto->id) {
+ case IPSEC_ESP_DES:
+ case IPSEC_ESP_DES_IV32:
+ case IPSEC_ESP_DES_IV64:
+ ssa.sadb_sa_encrypt = SADB_EALG_DESCBC;
+ break;
+
+ case IPSEC_ESP_3DES:
+ ssa.sadb_sa_encrypt = SADB_EALG_3DESCBC;
+ break;
+
+#ifdef SADB_X_EALG_AES
+ case IPSEC_ESP_AES:
+ /* case IPSEC_ESP_AES_128_CTR: */
+ ssa.sadb_sa_encrypt = SADB_X_EALG_AES;
+ break;
+#endif
+
+#ifdef SADB_X_EALG_CAST
+ case IPSEC_ESP_CAST:
+ ssa.sadb_sa_encrypt = SADB_X_EALG_CAST;
+ break;
+#endif
+
+#ifdef SADB_X_EALG_BLF
+ case IPSEC_ESP_BLOWFISH:
+ ssa.sadb_sa_encrypt = SADB_X_EALG_BLF;
+ break;
+#endif
+
+ default:
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: "
+ "unknown encryption algorithm %d", proto->id));
+ return -1;
+ }
+
+ switch (iproto->auth) {
+ case IPSEC_AUTH_HMAC_MD5:
+#ifdef SADB_AALG_MD5HMAC96
+ ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96;
+#else
+ ssa.sadb_sa_auth = SADB_AALG_MD5HMAC;
+#endif
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA:
+#ifdef SADB_AALG_SHA1HMAC96
+ ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96;
+#else
+ ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC;
+#endif
+ break;
+
+#ifndef KAME
+ case IPSEC_AUTH_HMAC_RIPEMD:
+#ifdef SADB_X_AALG_RIPEMD160HMAC96
+ ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96;
+#elif defined (SADB_X_AALG_RIPEMD160HMAC)
+ ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC;
+#elif defined (SADB_X_AALG_RIPEMD160)
+ ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160;
+#else
+ ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC;
+#endif
+ break;
+#endif
+
+#ifdef SADB_X_AALG_SHA2_256
+ case IPSEC_AUTH_HMAC_SHA2_256:
+ ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256;
+ break;
+#endif
+
+#ifdef SADB_X_AALG_SHA2_384
+ case IPSEC_AUTH_HMAC_SHA2_384:
+ ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384;
+ break;
+#endif
+
+#ifdef SADB_X_AALG_SHA2_512
+ case IPSEC_AUTH_HMAC_SHA2_512:
+ ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512;
+ break;
+#endif
+
+ case IPSEC_AUTH_DES_MAC:
+ case IPSEC_AUTH_KPDK:
+ /* XXX We should be supporting KPDK */
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: "
+ "unknown authentication algorithm %d",
+ iproto->auth));
+ return -1;
+
+ default:
+ ssa.sadb_sa_auth = SADB_AALG_NONE;
+ }
+ break;
+
+ case IPSEC_PROTO_IPSEC_AH:
+ msg.sadb_msg_satype = SADB_SATYPE_AH;
+ hashlen = ipsec_ah_keylength(proto);
+ keylen = 0;
+
+ ssa.sadb_sa_encrypt = SADB_EALG_NONE;
+ switch (proto->id) {
+ case IPSEC_AH_MD5:
+#ifdef SADB_AALG_MD5HMAC96
+ ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96;
+#else
+ ssa.sadb_sa_auth = SADB_AALG_MD5HMAC;
+#endif
+ break;
+
+ case IPSEC_AH_SHA:
+#ifdef SADB_AALG_SHA1HMAC96
+ ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96;
+#else
+ ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC;
+#endif
+ break;
+
+#ifndef KAME
+ case IPSEC_AH_RIPEMD:
+#ifdef SADB_X_AALG_RIPEMD160HMAC96
+ ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96;
+#elif defined (SADB_X_AALG_RIPEMD160HMAC)
+ ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC;
+#elif defined (SADB_X_AALG_RIPEMD160)
+ ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160;
+#else
+ ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC;
+#endif
+ break;
+#endif
+
+#ifdef SADB_X_AALG_SHA2_256
+ case IPSEC_AH_SHA2_256:
+ ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256;
+ break;
+#endif
+
+#ifdef SADB_X_AALG_SHA2_384
+ case IPSEC_AH_SHA2_384:
+ ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384;
+ break;
+#endif
+
+#ifdef SADB_X_AALG_SHA2_512
+ case IPSEC_AH_SHA2_512:
+ ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512;
+ break;
+#endif
+
+ default:
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: "
+ "unknown authentication algorithm %d", proto->id));
+ goto cleanup;
+ }
+ break;
+
+#ifdef SADB_X_SATYPE_IPCOMP
+ case IPSEC_PROTO_IPCOMP:
+ msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
+ ssa.sadb_sa_auth = SADB_AALG_NONE;
+ keylen = 0;
+ hashlen = 0;
+
+ /*
+ * Put compression algorithm type in the sadb_sa_encrypt
+ * field.
+ */
+ switch (proto->id) {
+#ifdef SADB_X_CALG_OUI
+ case IPSEC_IPCOMP_OUI:
+ ssa.sadb_sa_encrypt = SADB_X_CALG_OUI;
+ break;
+#endif
+
+#ifdef SADB_X_CALG_DEFLATE
+ case IPSEC_IPCOMP_DEFLATE:
+ ssa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE;
+ break;
+#endif
+
+#ifdef SADB_X_CALG_LZS
+ case IPSEC_IPCOMP_LZS:
+ ssa.sadb_sa_encrypt = SADB_X_CALG_LZS;
+ break;
+#endif
+
+#ifdef SADB_X_CALG_V42BIS
+ case IPSEC_IPCOMP_V42BIS:
+ ssa.sadb_sa_encrypt = SADB_X_CALG_V42BIS;
+ break;
+#endif
+
+ default:
+ break;
+ }
+ break;
+#endif /* SADB_X_SATYPE_IPCOMP */
+
+ default:
+ log_print("pf_key_v2_set_spi: invalid proto %d", proto->proto);
+ goto cleanup;
+ }
+ if (incoming) {
+ sa->transport->vtbl->get_src(sa->transport, &dst);
+ sa->transport->vtbl->get_dst(sa->transport, &src);
+ }
+ else {
+ sa->transport->vtbl->get_dst(sa->transport, &dst);
+ sa->transport->vtbl->get_src(sa->transport, &src);
+ }
+
+#ifdef KAME
+ msg.sadb_msg_seq = (incoming ?
+ pf_key_v2_seq_by_sa(proto->spi[incoming], sizeof ssa.sadb_sa_spi,
+ proto->proto, dst, sysdep_sa_len(dst)) : 0);
+#else
+ msg.sadb_msg_seq = sa->seq;
+#endif
+ update = pf_key_v2_msg_new(&msg, 0);
+ if (!update)
+ goto cleanup;
+
+#ifdef KAME
+ memset(&ssa2, 0, sizeof ssa2);
+ ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;
+#if defined (LINUX_IPSEC)
+ if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL)
+ ssa2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL;
+ else
+ ssa2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT;
+#else
+ ssa2.sadb_x_sa2_mode = 0;
+#endif
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa2, 0) == -1)
+ goto cleanup;
+#endif
+
+ /* Setup the rest of the SA extension. */
+ ssa.sadb_sa_exttype = SADB_EXT_SA;
+ ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK;
+ if (proto->spi_sz[incoming] == 2) /* IPCOMP uses 16bit CPIs. */
+ ssa.sadb_sa_spi = htonl(proto->spi[incoming][0] << 8 |
+ proto->spi[incoming][1]);
+ else
+ memcpy(&ssa.sadb_sa_spi, proto->spi[incoming],
+ sizeof ssa.sadb_sa_spi);
+ ssa.sadb_sa_replay = conf_get_str("General", "Shared-SADB") ? 0 :
+ iproto->replay_window;
+ ssa.sadb_sa_state = SADB_SASTATE_MATURE;
+ ssa.sadb_sa_flags = 0;
+#ifdef SADB_X_SAFLAGS_TUNNEL
+ if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL ||
+ iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL ||
+ iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL_DRAFT)
+ ssa.sadb_sa_flags = SADB_X_SAFLAGS_TUNNEL;
+#endif
+
+ if (isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) {
+#if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP)
+ memset(&udpencap, 0, sizeof udpencap);
+ ssa.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP;
+ udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP;
+ udpencap.sadb_x_udpencap_len =
+ sizeof udpencap / PF_KEY_V2_CHUNK;
+ udpencap.sadb_x_udpencap_port = sockaddr_port(dst);
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *)&udpencap, 0)
+ == -1)
+ goto cleanup;
+#elif defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_NAT_T_TYPE)
+#ifndef UDP_ENCAP_ESPINUDP
+#define UDP_ENCAP_ESPINUDP 2
+#endif
+ memset(&nat_t_type, 0, sizeof nat_t_type);
+ memset(&nat_t_sport, 0, sizeof nat_t_sport);
+ memset(&nat_t_dport, 0, sizeof nat_t_dport);
+
+ /* type = draft-udp-encap-06 */
+ nat_t_type.sadb_x_nat_t_type_len = sizeof nat_t_type / PF_KEY_V2_CHUNK;
+ nat_t_type.sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+ nat_t_type.sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP;
+ if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_type, 0) == -1)
+ goto cleanup;
+
+ /* source port */
+ nat_t_sport.sadb_x_nat_t_port_len = sizeof nat_t_sport /
+ PF_KEY_V2_CHUNK;
+ nat_t_sport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
+ nat_t_sport.sadb_x_nat_t_port_port = sockaddr_port(src);
+ if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_sport, 0) == -1)
+ goto cleanup;
+
+ /* destination port */
+ nat_t_dport.sadb_x_nat_t_port_len = sizeof nat_t_dport /
+ PF_KEY_V2_CHUNK;
+ nat_t_dport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
+ nat_t_dport.sadb_x_nat_t_port_port = sockaddr_port(dst);
+ if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_dport, 0) == -1)
+ goto cleanup;
+
+ /* original address (transport mode checksum missing info) goes here */
+#endif
+ }
+
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa, 0) == -1)
+ goto cleanup;
+
+ if (sa->seconds || sa->kilobytes) {
+ /* Setup the hard limits. */
+ life = malloc(sizeof *life);
+ if (!life)
+ goto cleanup;
+ life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK;
+ life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
+ life->sadb_lifetime_allocations = 0;
+ life->sadb_lifetime_bytes = sa->kilobytes * 1024;
+ /*
+ * XXX I am not sure which one is best in security respect.
+ * Maybe the RFCs actually mandate what a lifetime really is.
+ */
+#if 0
+ life->sadb_lifetime_addtime = 0;
+ life->sadb_lifetime_usetime = sa->seconds;
+#else
+ life->sadb_lifetime_addtime = sa->seconds;
+ life->sadb_lifetime_usetime = 0;
+#endif
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) life,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ life = 0;
+
+ /*
+ * Setup the soft limits, we use 90 % of the hard ones.
+ * XXX A configurable ratio would be better.
+ */
+ life = malloc(sizeof *life);
+ if (!life)
+ goto cleanup;
+ life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK;
+ life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
+ life->sadb_lifetime_allocations = 0;
+ life->sadb_lifetime_bytes = sa->kilobytes * 1024 * 9 / 10;
+ /*
+ * XXX I am not sure which one is best in security respect.
+ * Maybe the RFCs actually mandate what a lifetime really is.
+ */
+#if 0
+ life->sadb_lifetime_addtime = 0;
+ life->sadb_lifetime_usetime = sa->seconds * 9 / 10;
+#else
+ life->sadb_lifetime_addtime = sa->seconds * 9 / 10;
+ life->sadb_lifetime_usetime = 0;
+#endif
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) life,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ life = 0;
+ }
+ /*
+ * Setup the ADDRESS extensions.
+ */
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, src, sysdep_sa_len(src));
+ switch (((struct sockaddr *) (addr + 1))->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
+ break;
+ }
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, dst, sysdep_sa_len(dst));
+ switch (((struct sockaddr *) (addr + 1))->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
+ break;
+ }
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+#if 0
+ /* XXX I am not sure about what to do here just yet. */
+ if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) {
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, dst, sysdep_sa_len(dst));
+ switch (((struct sockaddr *) (addr + 1))->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
+ break;
+ }
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+#if 0
+ msg->em_odst = msg->em_dst;
+ msg->em_osrc = msg->em_src;
+#endif
+ }
+#endif
+
+ if (proto->proto != IPSEC_PROTO_IPCOMP) {
+ /* Setup the KEY extensions. */
+ if (hashlen) {
+ len = sizeof *key + PF_KEY_V2_ROUND(hashlen);
+ key = malloc(len);
+ if (!key)
+ goto cleanup;
+ key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
+ key->sadb_key_len = len / PF_KEY_V2_CHUNK;
+ key->sadb_key_bits = hashlen * 8;
+ key->sadb_key_reserved = 0;
+ memcpy(key + 1,
+ iproto->keymat[incoming] +
+ (proto->proto ==
+ IPSEC_PROTO_IPSEC_ESP ? keylen : 0),
+ hashlen);
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) key,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ key = 0;
+ }
+ if (keylen) {
+ len = sizeof *key + PF_KEY_V2_ROUND(keylen);
+ key = malloc(len);
+ if (!key)
+ goto cleanup;
+ key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
+ key->sadb_key_len = len / PF_KEY_V2_CHUNK;
+ key->sadb_key_bits = keylen * 8;
+ key->sadb_key_reserved = 0;
+ memcpy(key + 1, iproto->keymat[incoming], keylen);
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) key,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ key = 0;
+ }
+ }
+#ifndef KAME
+ /* Setup identity extensions. */
+ if (isakmp_sa->id_i) {
+ pp = pf_key_v2_convert_id(isakmp_sa->id_i, isakmp_sa->id_i_len,
+ &len, &idtype);
+ if (!pp)
+ goto nosid;
+
+ sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid,
+ sizeof(u_int8_t));
+ if (!sid) {
+ free(pp);
+ goto cleanup;
+ }
+ sid->sadb_ident_type = idtype;
+ sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) +
+ PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK;
+ if ((isakmp_sa->initiator && !incoming) ||
+ (!isakmp_sa->initiator && incoming))
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
+ else
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
+
+ memcpy(sid + 1, pp, len);
+ free(pp);
+
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ sid = 0;
+
+nosid:
+ if (sid)
+ free(sid);
+ sid = 0;
+ }
+ if (isakmp_sa->id_r) {
+ pp = pf_key_v2_convert_id(isakmp_sa->id_r, isakmp_sa->id_r_len,
+ &len, &idtype);
+ if (!pp)
+ goto nodid;
+
+ sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid,
+ sizeof(u_int8_t));
+ if (!sid) {
+ free(pp);
+ goto cleanup;
+ }
+ sid->sadb_ident_type = idtype;
+ sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) +
+ PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK;
+ if ((isakmp_sa->initiator && !incoming) ||
+ (!isakmp_sa->initiator && incoming))
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
+ else
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
+
+ memcpy(sid + 1, pp, len);
+ free(pp);
+
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ sid = 0;
+
+nodid:
+ if (sid)
+ free(sid);
+ sid = 0;
+ }
+#endif /* KAME */
+
+#ifdef SADB_X_CREDTYPE_NONE
+ /*
+ * Send received credentials to the kernel. We don't bother with
+ * our credentials, since the process either knows them (if it
+ * specified them with setsockopt()), or has no business looking at
+ * them (e.g., system wide certs).
+ */
+ if (isakmp_sa->recv_cert) {
+ switch (isakmp_sa->recv_certtype) {
+ case ISAKMP_CERTENC_NONE:
+ /* Nothing to be done here. */
+ break;
+
+#if defined (USE_KEYNOTE) && defined (SADB_X_EXT_REMOTE_CREDENTIALS)
+ case ISAKMP_CERTENC_KEYNOTE:
+ len = strlen(isakmp_sa->recv_cert);
+ cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred,
+ sizeof(u_int8_t));
+ if (!cred)
+ goto cleanup;
+
+ cred->sadb_x_cred_len =
+ ((sizeof *cred) / PF_KEY_V2_CHUNK) +
+ PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK;
+ cred->sadb_x_cred_exttype =
+ SADB_X_EXT_REMOTE_CREDENTIALS;
+ cred->sadb_x_cred_type = SADB_X_CREDTYPE_KEYNOTE;
+ memcpy(cred + 1, isakmp_sa->recv_cert, len);
+
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ break;
+#endif /* USE_KEYNOTE */
+
+#if defined (USE_X509) && defined (SADB_X_EXT_REMOTE_CREDENTIALS)
+ case ISAKMP_CERTENC_X509_SIG:
+ {
+ u_int8_t *data;
+ u_int32_t datalen;
+ struct cert_handler *handler;
+
+ /* We do it this way to avoid weird includes.*/
+ handler = cert_get(ISAKMP_CERTENC_X509_SIG);
+ if (!handler)
+ break;
+ handler->cert_serialize(isakmp_sa->recv_cert,
+ &data, &datalen);
+ if (!data)
+ break;
+
+ len = datalen;
+ cred =
+ calloc(PF_KEY_V2_ROUND(len) + sizeof *cred,
+ sizeof(u_int8_t));
+ if (!cred) {
+ free(data);
+ goto cleanup;
+ }
+ cred->sadb_x_cred_len =
+ ((sizeof *cred) / PF_KEY_V2_CHUNK) +
+ PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK;
+ cred->sadb_x_cred_exttype =
+ SADB_X_EXT_REMOTE_CREDENTIALS;
+ cred->sadb_x_cred_type = SADB_X_CREDTYPE_X509;
+ memcpy(cred + 1, data, len);
+ free(data);
+
+ if (pf_key_v2_msg_add(update,
+ (struct sadb_ext *) cred,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ }
+ break;
+#endif /* USE_X509 */
+ }
+ }
+#endif /* SADB_X_CREDTYPE_NONE */
+
+#ifdef SADB_X_AUTHTYPE_NONE
+ /*
+ * Tell the kernel what the peer used to authenticate, unless it was a
+ * passphrase.
+ */
+ if (isakmp_sa->recv_key) {
+ u_int8_t *data;
+
+ /*
+ * If it's a private key, we shouldn't pass it to the kernel
+ * for processes to see; successful authentication of Phase 1
+ * implies that the process already knew the passphrase. On
+ * the other hand, we don't want to reveal to processes any
+ * system-wide passphrases used for authentication with remote
+ * systems. Same reason we don't send up the key (private or
+ * passphrase) we used to authenticate with the peer.
+ */
+ if (isakmp_sa->recv_keytype == ISAKMP_KEY_PASSPHRASE)
+ goto doneauth;
+
+ key_serialize(isakmp_sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC,
+ isakmp_sa->recv_key, &data, &len);
+ if (!data)
+ goto cleanup;
+
+ cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred,
+ sizeof(u_int8_t));
+ if (!cred) {
+ free(data);
+ goto cleanup;
+ }
+ cred->sadb_x_cred_len = ((sizeof *cred) / PF_KEY_V2_CHUNK) +
+ PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK;
+ cred->sadb_x_cred_exttype = SADB_X_EXT_REMOTE_AUTH;
+ memcpy(cred + 1, data, len);
+ free(data);
+
+ switch (isakmp_sa->recv_keytype) {
+ case ISAKMP_KEY_RSA:
+ cred->sadb_x_cred_type = SADB_X_AUTHTYPE_RSA;
+ break;
+
+ default:
+ log_print("pf_key_v2_set_spi: "
+ "unknown received key type %d",
+ isakmp_sa->recv_keytype);
+ free(cred);
+ goto cleanup;
+ }
+
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ }
+doneauth:
+#endif /* SADB_X_AUTHTYPE_NONE */
+
+#ifdef SADB_X_EXT_FLOW_TYPE
+ /* Setup the flow type extension. */
+ bzero(&flowtype, sizeof flowtype);
+ flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE;
+ flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK;
+ flowtype.sadb_protocol_direction = incoming ?
+ IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT;
+
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *)&flowtype, 0) == -1)
+ goto cleanup;
+
+ bzero(&tprotocol, sizeof tprotocol);
+ tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
+ tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK;
+ tprotocol.sadb_protocol_proto = isa->tproto;
+
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *)&tprotocol,
+ 0) == -1)
+ goto cleanup;
+
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(isa->src_net));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = incoming ?
+ SADB_X_EXT_DST_FLOW : SADB_X_EXT_SRC_FLOW;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+ pf_key_v2_setup_sockaddr(addr + 1, isa->src_net, 0, isa->sport, 0);
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype =
+ incoming ? SADB_X_EXT_DST_MASK : SADB_X_EXT_SRC_MASK;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+ pf_key_v2_setup_sockaddr(addr + 1, isa->src_mask, 0,
+ isa->sport ? 0xffff : 0, 0);
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = incoming ?
+ SADB_X_EXT_SRC_FLOW : SADB_X_EXT_DST_FLOW;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+ pf_key_v2_setup_sockaddr(addr + 1, isa->dst_net, 0, isa->dport, 0);
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype =
+ incoming ? SADB_X_EXT_SRC_MASK : SADB_X_EXT_DST_MASK;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+ pf_key_v2_setup_sockaddr(addr + 1, isa->dst_mask, 0,
+ isa->dport ? 0xffff : 0, 0);
+ if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+#endif /* SADB_X_EXT_FLOW_TYPE */
+
+ /* XXX Here can sensitivity extensions be setup. */
+
+#ifdef USE_DEBUG
+ if (sockaddr2text(dst, &addr_str, 0))
+ addr_str = 0;
+
+ LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_set_spi: "
+ "satype %d dst %s SPI 0x%x", msg.sadb_msg_satype,
+ addr_str ? addr_str : "unknown", ntohl(ssa.sadb_sa_spi)));
+
+ if (addr_str)
+ free(addr_str);
+#endif /* USE_DEBUG */
+
+ /*
+ * Although PF_KEY knows about expirations, it is unreliable per the
+ * specs thus we need to do them inside isakmpd as well.
+ */
+ if (sa->seconds)
+ if (sa_setup_expirations(sa))
+ goto cleanup;
+
+ ret = pf_key_v2_call(update);
+ pf_key_v2_msg_free(update);
+ update = 0;
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ pf_key_v2_msg_free(ret);
+ ret = 0;
+
+ /*
+ * If we are doing an addition into an SADB shared with our peer,
+ * errors here are to be expected as the peer will already have
+ * created the SA, and can thus be ignored.
+ */
+ if (err && !(msg.sadb_msg_type == SADB_ADD &&
+ conf_get_str("General", "Shared-SADB"))) {
+ log_print("pf_key_v2_set_spi: %s: %s",
+ msg.sadb_msg_type == SADB_ADD ? "ADD" : "UPDATE",
+ strerror(err));
+ goto cleanup;
+ }
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: done"));
+
+ return 0;
+
+cleanup:
+ if (sid)
+ free(sid);
+ if (addr)
+ free(addr);
+ if (life)
+ free(life);
+ if (key)
+ free(key);
+ if (update)
+ pf_key_v2_msg_free(update);
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return -1;
+}
+
+static __inline__ int
+pf_key_v2_mask_to_bits(u_int32_t mask)
+{
+ u_int32_t hmask = ntohl(mask);
+
+ return (33 - ffs(~hmask + 1)) % 33;
+}
+
+static int
+pf_key_v2_mask6_to_bits(u_int8_t * mask)
+{
+ int n;
+
+ bit_ffc(mask, 128, &n);
+ return n == -1 ? 128 : n;
+}
+
+/*
+ * Enable/disable a flow.
+ * XXX Assumes OpenBSD {ADD,DEL}FLOW extensions.
+ * Should probably be moved to sysdep.c
+ */
+static int
+pf_key_v2_flow(struct sockaddr *laddr, struct sockaddr *lmask,
+ struct sockaddr *raddr, struct sockaddr *rmask,
+ u_int8_t tproto, u_int16_t sport, u_int16_t dport,
+ u_int8_t *spi, u_int8_t proto, struct sockaddr *dst,
+ struct sockaddr *src, int delete, int ingress,
+ u_int8_t srcid_type, u_int8_t *srcid, int srcid_len,
+ u_int8_t dstid_type, u_int8_t *dstid, int dstid_len,
+ struct ipsec_proto *iproto)
+{
+#ifdef USE_DEBUG
+ char *laddr_str, *lmask_str, *raddr_str, *rmask_str;
+#endif
+
+#if defined (SADB_X_ADDFLOW) && defined (SADB_X_DELFLOW)
+ struct sadb_msg msg;
+#if defined (SADB_X_EXT_FLOW_TYPE)
+ struct sadb_protocol flowtype;
+ struct sadb_ident *sid = 0;
+#else
+ struct sadb_sa ssa;
+#endif
+ struct sadb_address *addr = 0;
+ struct sadb_protocol tprotocol;
+ struct pf_key_v2_msg *flow = 0, *ret = 0;
+ size_t len;
+ int err;
+
+#if !defined (SADB_X_SAFLAGS_INGRESS_FLOW) && !defined (SADB_X_EXT_FLOW_TYPE)
+ if (ingress)
+ return 0;
+#endif
+
+ msg.sadb_msg_type = delete ? SADB_X_DELFLOW : SADB_X_ADDFLOW;
+ switch (proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ break;
+ case IPSEC_PROTO_IPSEC_AH:
+ msg.sadb_msg_satype = SADB_SATYPE_AH;
+ break;
+ case IPSEC_PROTO_IPCOMP:
+ msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
+ break;
+ default:
+ log_print("pf_key_v2_flow: invalid proto %d", proto);
+ goto cleanup;
+ }
+ msg.sadb_msg_seq = 0;
+ flow = pf_key_v2_msg_new(&msg, 0);
+ if (!flow)
+ goto cleanup;
+
+#if defined (SADB_X_EXT_FLOW_TYPE)
+ if (!delete) {
+ /* Setup the source ID, if provided. */
+ if (srcid) {
+ sid = calloc(
+ PF_KEY_V2_ROUND(srcid_len + 1) + sizeof *sid,
+ sizeof(u_int8_t));
+ if (!sid)
+ goto cleanup;
+
+ sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK)
+ + PF_KEY_V2_ROUND(srcid_len + 1) / PF_KEY_V2_CHUNK;
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
+ sid->sadb_ident_type = srcid_type;
+
+ memcpy(sid + 1, srcid, srcid_len);
+
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+
+ sid = 0;
+ }
+ /* Setup the destination ID, if provided. */
+ if (dstid) {
+ sid = calloc(
+ PF_KEY_V2_ROUND(dstid_len + 1) + sizeof *sid,
+ sizeof(u_int8_t));
+ if (!sid)
+ goto cleanup;
+
+ sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK)
+ + PF_KEY_V2_ROUND(dstid_len + 1) / PF_KEY_V2_CHUNK;
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
+ sid->sadb_ident_type = dstid_type;
+
+ memcpy(sid + 1, dstid, dstid_len);
+
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+
+ sid = 0;
+ }
+ }
+ /* Setup the flow type extension. */
+ bzero(&flowtype, sizeof flowtype);
+ flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE;
+ flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK;
+ flowtype.sadb_protocol_direction =
+ ingress ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT;
+ flowtype.sadb_protocol_proto =
+ ingress ? SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE;
+
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&flowtype, 0) == -1)
+ goto cleanup;
+#else /* SADB_X_EXT_FLOW_TYPE */
+ /* Setup the SA extension. */
+ ssa.sadb_sa_exttype = SADB_EXT_SA;
+ ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK;
+ memcpy(&ssa.sadb_sa_spi, spi, sizeof ssa.sadb_sa_spi);
+ ssa.sadb_sa_replay = 0;
+ ssa.sadb_sa_state = 0;
+ ssa.sadb_sa_auth = 0;
+ ssa.sadb_sa_encrypt = 0;
+ ssa.sadb_sa_flags = 0;
+#if defined (SADB_X_SAFLAGS_INGRESS_FLOW)
+ if (ingress)
+ ssa.sadb_sa_flags |= SADB_X_SAFLAGS_INGRESS_FLOW;
+#endif
+#if defined (SADB_X_SAFLAGS_REPLACEFLOW)
+ if (!delete && !ingress)
+ ssa.sadb_sa_flags |= SADB_X_SAFLAGS_REPLACEFLOW;
+#endif
+
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa, 0) == -1)
+ goto cleanup;
+#endif /* SADB_X_EXT_FLOW_TYPE */
+
+ /*
+ * Setup the ADDRESS extensions.
+ */
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src));
+#if !defined (SADB_X_EXT_FLOW_TYPE)
+ if (!delete || ingress)
+#else
+ if (!delete)
+#endif /* SADB_X_EXT_FLOW_TYPE */
+ {
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+#if defined (SADB_X_EXT_FLOW_TYPE)
+ pf_key_v2_setup_sockaddr(addr + 1, src, dst, 0, ingress);
+#else
+ pf_key_v2_setup_sockaddr(addr + 1, dst, 0, 0, 0);
+#endif
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+ }
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(laddr));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_X_EXT_SRC_FLOW;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+ pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0);
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_X_EXT_SRC_MASK;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+ pf_key_v2_setup_sockaddr(addr + 1, lmask, 0, sport ? 0xffff : 0, 0);
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_X_EXT_DST_FLOW;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+ pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0);
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_X_EXT_DST_MASK;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+ addr->sadb_address_reserved = 0;
+ pf_key_v2_setup_sockaddr(addr + 1, rmask, 0, dport ? 0xffff : 0, 0);
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ /* Setup the protocol extension. */
+ bzero(&tprotocol, sizeof tprotocol);
+ tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
+ tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK;
+ tprotocol.sadb_protocol_proto = tproto;
+
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&tprotocol, 0) == -1)
+ goto cleanup;
+
+#ifdef USE_DEBUG
+ if (sockaddr2text(laddr, &laddr_str, 0))
+ laddr_str = 0;
+ if (sockaddr2text(lmask, &lmask_str, 0))
+ lmask_str = 0;
+ if (sockaddr2text(raddr, &raddr_str, 0))
+ raddr_str = 0;
+ if (sockaddr2text(rmask, &rmask_str, 0))
+ rmask_str = 0;
+
+ LOG_DBG((LOG_SYSDEP, 50,
+ "pf_key_v2_flow: src %s %s dst %s %s proto %u sport %u dport %u",
+ laddr_str ? laddr_str : "<??\?>", lmask_str ? lmask_str : "<??\?>",
+ raddr_str ? raddr_str : "<??\?>", rmask_str ? rmask_str : "<??\?>",
+ tproto, ntohs(sport), ntohs(dport)));
+
+ if (laddr_str)
+ free(laddr_str);
+ if (lmask_str)
+ free(lmask_str);
+ if (raddr_str)
+ free(raddr_str);
+ if (rmask_str)
+ free(rmask_str);
+#endif /* USE_DEBUG */
+
+ ret = pf_key_v2_call(flow);
+ pf_key_v2_msg_free(flow);
+ flow = 0;
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (err) {
+ if (err == ESRCH) /* These are common and usually
+ * harmless. */
+ LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_flow: %sFLOW: %s",
+ delete ? "DEL" : "ADD", strerror(err)));
+ else
+ log_print("pf_key_v2_flow: %sFLOW: %s",
+ delete ? "DEL" : "ADD", strerror(err));
+ goto cleanup;
+ }
+ pf_key_v2_msg_free(ret);
+
+ LOG_DBG((LOG_MISC, 50, "pf_key_v2_flow: %sFLOW: done",
+ delete ? "DEL" : "ADD"));
+
+ return 0;
+
+cleanup:
+#if defined (SADB_X_EXT_FLOW_TYPE)
+ if (sid)
+ free(sid);
+#endif /* SADB_X_EXT_FLOW_TYPE */
+ if (addr)
+ free(addr);
+ if (flow)
+ pf_key_v2_msg_free(flow);
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return -1;
+
+#elif defined (SADB_X_SPDUPDATE) && defined (SADB_X_SPDDELETE)
+ struct sadb_msg msg;
+ struct sadb_x_policy *policy = 0;
+ struct sadb_x_ipsecrequest *ipsecrequest;
+ struct sadb_x_sa2 ssa2;
+ struct sadb_address *addr = 0;
+ struct sockaddr *saddr;
+ struct pf_key_v2_msg *flow = 0, *ret = 0;
+ u_int8_t *policy_buf;
+ size_t len;
+ int err;
+ struct sockaddr_in *ip4_sa;
+ struct sockaddr_in6 *ip6_sa;
+
+ msg.sadb_msg_type = delete ? SADB_X_SPDDELETE : SADB_X_SPDUPDATE;
+ msg.sadb_msg_satype = SADB_SATYPE_UNSPEC;
+ msg.sadb_msg_seq = 0;
+ flow = pf_key_v2_msg_new(&msg, 0);
+ if (!flow)
+ goto cleanup;
+
+ memset(&ssa2, 0, sizeof ssa2);
+ ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;
+ ssa2.sadb_x_sa2_mode = 0;
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa2, 0) == -1)
+ goto cleanup;
+
+ /*
+ * Setup the ADDRESS extensions.
+ */
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifdef LINUX_IPSEC
+ addr->sadb_address_proto = tproto;
+#else
+ addr->sadb_address_proto = IPSEC_ULPROTO_ANY;
+#endif
+ addr->sadb_address_reserved = 0;
+#ifdef LINUX_IPSEC
+ pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0);
+#else
+ pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, IPSEC_PORT_ANY, 0);
+#endif
+ switch (laddr->sa_family) {
+ case AF_INET:
+ ip4_sa = (struct sockaddr_in *) lmask;
+ addr->sadb_address_prefixlen
+ = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ ip6_sa = (struct sockaddr_in6 *) lmask;
+ addr->sadb_address_prefixlen =
+ pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]);
+ break;
+ }
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(raddr));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifdef LINUX_IPSEC
+ addr->sadb_address_proto = tproto;
+#else
+ addr->sadb_address_proto = IPSEC_ULPROTO_ANY;
+#endif
+ addr->sadb_address_reserved = 0;
+#ifdef LINUX_IPSEC
+ pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0);
+#else
+ pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, IPSEC_PORT_ANY, 0);
+#endif
+ switch (raddr->sa_family) {
+ case AF_INET:
+ ip4_sa = (struct sockaddr_in *) rmask;
+ addr->sadb_address_prefixlen
+ = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ ip6_sa = (struct sockaddr_in6 *) rmask;
+ addr->sadb_address_prefixlen =
+ pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]);
+ break;
+ }
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ /* Setup the POLICY extension. */
+ len = sizeof *policy + sizeof *ipsecrequest +
+ 2 * PF_KEY_V2_ROUND(sysdep_sa_len(src));
+ policy_buf = (u_int8_t *) calloc(1, len);
+ if (!policy_buf) {
+ log_error("pf_key_v2_flow: calloc %lu failed",
+ (unsigned long) len);
+ goto cleanup;
+ }
+ policy = (struct sadb_x_policy *) policy_buf;
+ policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ policy->sadb_x_policy_len = len / PF_KEY_V2_CHUNK;
+ policy->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+ if (ingress)
+ policy->sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+ else
+ policy->sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
+ policy->sadb_x_policy_reserved = 0;
+
+ /* Setup the IPSECREQUEST extension part. */
+ ipsecrequest = (struct sadb_x_ipsecrequest *) (policy + 1);
+ ipsecrequest->sadb_x_ipsecrequest_len = len - sizeof *policy;
+ switch (proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_ESP;
+ break;
+ case IPSEC_PROTO_IPSEC_AH:
+ ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_AH;
+ break;
+ default:
+ log_print("pf_key_v2_flow: invalid proto %d", proto);
+ goto cleanup;
+ }
+#if defined (LINUX_IPSEC)
+ if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL)
+ ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL;
+ else
+ ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT;
+#else
+ ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; /* XXX */
+#endif
+ ipsecrequest->sadb_x_ipsecrequest_level
+ = ingress ? IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE;
+ ipsecrequest->sadb_x_ipsecrequest_reqid = 0; /* XXX */
+
+ /* Add source and destination addresses. */
+ saddr = (struct sockaddr *)(ipsecrequest + 1);
+ pf_key_v2_setup_sockaddr(saddr, src, 0, 0, 0);
+ switch (src->sa_family) {
+ case AF_INET:
+ saddr = (struct sockaddr *)((struct sockaddr_in *)saddr + 1);
+ break;
+ case AF_INET6:
+ saddr = (struct sockaddr *)((struct sockaddr_in6 *)saddr + 1);
+ break;
+ }
+ pf_key_v2_setup_sockaddr(saddr, dst, 0, 0, 0);
+ if (pf_key_v2_msg_add(flow, (struct sadb_ext *)policy,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ policy = 0;
+
+#ifdef USE_DEBUG
+ if (sockaddr2text(laddr, &laddr_str, 0))
+ laddr_str = 0;
+ if (sockaddr2text(lmask, &lmask_str, 0))
+ lmask_str = 0;
+ if (sockaddr2text(raddr, &raddr_str, 0))
+ raddr_str = 0;
+ if (sockaddr2text(rmask, &rmask_str, 0))
+ rmask_str = 0;
+
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: src %s %s dst %s %s",
+ laddr_str ? laddr_str : "<??\?>", lmask_str ? lmask_str : "<??\?>",
+ raddr_str ? raddr_str : "<??\?>",
+ rmask_str ? rmask_str : "<??\?>"));
+
+ if (laddr_str)
+ free(laddr_str);
+ if (lmask_str)
+ free(lmask_str);
+ if (raddr_str)
+ free(raddr_str);
+ if (rmask_str)
+ free(rmask_str);
+#endif
+
+ ret = pf_key_v2_call(flow);
+ pf_key_v2_msg_free(flow);
+ flow = 0;
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (!delete && err == EEXIST) {
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: "
+ "SPDADD returns EEXIST"));
+ } else if (err) {
+ log_print("pf_key_v2_flow: SPD%s: %s",
+ delete ? "DELETE" : "ADD", strerror(err));
+ goto cleanup;
+ }
+ pf_key_v2_msg_free(ret);
+
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: SPD%s: done",
+ delete ? "DELETE" : "ADD"));
+
+ return 0;
+
+cleanup:
+ if (addr)
+ free(addr);
+ if (policy)
+ free(policy);
+ if (flow)
+ pf_key_v2_msg_free(flow);
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return -1;
+
+#else
+ log_print("pf_key_v2_flow: not supported in pure PF_KEYv2");
+ return -1;
+#endif
+}
+
+#ifndef KAME
+static u_int8_t *
+pf_key_v2_convert_id(u_int8_t * id, int idlen, size_t * reslen, int *idtype)
+{
+ u_int8_t *addr, *res = 0;
+ char addrbuf[ADDRESS_MAX + 5];
+
+ switch (id[0]) {
+ case IPSEC_ID_FQDN:
+ res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ,
+ sizeof(u_int8_t));
+ if (!res)
+ return 0;
+
+ *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ;
+ memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen);
+ *idtype = SADB_IDENTTYPE_FQDN;
+ LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: FQDN %.*s",
+ (int) *reslen, res));
+ return res;
+
+ case IPSEC_ID_USER_FQDN:
+ res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ,
+ sizeof(u_int8_t));
+ if (!res)
+ return 0;
+
+ *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ;
+ memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen);
+ *idtype = SADB_IDENTTYPE_USERFQDN;
+ LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: UFQDN %.*s",
+ (int) *reslen, res));
+ return res;
+
+ case IPSEC_ID_IPV4_ADDR: /* XXX CONNECTION ? */
+ if (inet_ntop(AF_INET, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ addrbuf, ADDRESS_MAX) == NULL)
+ return 0;
+ *reslen = strlen(addrbuf) + 3;
+ strlcat(addrbuf, "/32", ADDRESS_MAX + 5);
+ res = (u_int8_t *) strdup(addrbuf);
+ if (!res)
+ return 0;
+ *idtype = SADB_IDENTTYPE_PREFIX;
+ LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: "
+ "IPv4 address %s", res));
+ return res;
+
+ case IPSEC_ID_IPV6_ADDR: /* XXX CONNECTION ? */
+ if (inet_ntop(AF_INET6,
+ id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ addrbuf, ADDRESS_MAX) == NULL)
+ return 0;
+ *reslen = strlen(addrbuf) + 4;
+ strlcat(addrbuf, "/128", ADDRESS_MAX + 5);
+ res = (u_int8_t *) strdup(addrbuf);
+ if (!res)
+ return 0;
+ LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: "
+ "IPv6 address %s", res));
+ *idtype = SADB_IDENTTYPE_PREFIX;
+ return res;
+
+ case IPSEC_ID_IPV4_ADDR_SUBNET: /* XXX PREFIX */
+ addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+ if (inet_ntop(AF_INET, addr, addrbuf, ADDRESS_MAX) == NULL)
+ return 0;
+ snprintf(addrbuf + strlen(addrbuf),
+ ADDRESS_MAX - strlen(addrbuf), "/%d",
+ pf_key_v2_mask_to_bits(*(u_int32_t *)(addr +
+ sizeof(struct in_addr))));
+ *reslen = strlen(addrbuf);
+ res = (u_int8_t *) strdup(addrbuf);
+ if (!res)
+ return 0;
+ *idtype = SADB_IDENTTYPE_PREFIX;
+ LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: "
+ "IPv4 subnet %s", res));
+ return res;
+
+ case IPSEC_ID_IPV6_ADDR_SUBNET: /* XXX PREFIX */
+ addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+ if (inet_ntop(AF_INET6, addr, addrbuf, ADDRESS_MAX) == NULL)
+ return 0;
+ snprintf(addrbuf + strlen(addrbuf),
+ ADDRESS_MAX - strlen(addrbuf), "/%d",
+ pf_key_v2_mask6_to_bits(addr +
+ sizeof(struct in6_addr)));
+ *reslen = strlen(addrbuf);
+ res = (u_int8_t *) strdup(addrbuf);
+ if (!res)
+ return 0;
+ LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: "
+ "IPv6 subnet %s", res));
+ *idtype = SADB_IDENTTYPE_PREFIX;
+ return res;
+
+ case IPSEC_ID_IPV4_RANGE:
+ case IPSEC_ID_IPV6_RANGE:
+ case IPSEC_ID_DER_ASN1_DN:
+ case IPSEC_ID_DER_ASN1_GN:
+ case IPSEC_ID_KEY_ID:
+ /* XXX Not implemented yet. */
+ return 0;
+ }
+
+ return 0;
+}
+#endif
+
+/* Enable a flow given an SA. */
+int
+pf_key_v2_enable_sa(struct sa *sa, struct sa *isakmp_sa)
+{
+ struct ipsec_sa *isa = sa->data;
+ struct sockaddr *dst, *src;
+ int error;
+ struct proto *proto = TAILQ_FIRST(&sa->protos);
+ int sidtype = 0, didtype = 0;
+ size_t sidlen = 0, didlen = 0;
+ u_int8_t *sid = 0, *did = 0;
+#if !defined (SADB_X_EXT_FLOW_TYPE)
+ struct sockaddr_storage hostmask_storage;
+ struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage;
+#endif /* SADB_X_EXT_FLOW_TYPE */
+
+ sa->transport->vtbl->get_dst(sa->transport, &dst);
+ sa->transport->vtbl->get_src(sa->transport, &src);
+
+#if defined (SADB_X_EXT_FLOW_TYPE)
+ if (isakmp_sa->id_i) {
+ if (isakmp_sa->initiator)
+ sid = pf_key_v2_convert_id(isakmp_sa->id_i,
+ isakmp_sa->id_i_len, &sidlen, &sidtype);
+ else
+ did = pf_key_v2_convert_id(isakmp_sa->id_i,
+ isakmp_sa->id_i_len, &didlen, &didtype);
+ }
+ if (isakmp_sa->id_r) {
+ if (isakmp_sa->initiator)
+ did = pf_key_v2_convert_id(isakmp_sa->id_r,
+ isakmp_sa->id_r_len, &didlen, &didtype);
+ else
+ sid = pf_key_v2_convert_id(isakmp_sa->id_r,
+ isakmp_sa->id_r_len, &sidlen, &sidtype);
+ }
+#endif /* SADB_X_EXT_FLOW_TYPE */
+
+ error = pf_key_v2_flow(isa->src_net, isa->src_mask, isa->dst_net,
+ isa->dst_mask, isa->tproto, isa->sport, isa->dport,
+ proto->spi[0], proto->proto, dst, src, 0, 0,
+ sidtype, sid, sidlen, didtype, did, didlen,
+ proto->data);
+ if (error)
+ goto cleanup;
+
+#if !defined (SADB_X_EXT_FLOW_TYPE)
+ /* Set hostmask to '-1'. */
+ switch (dst->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) hostmask)->sin_family = AF_INET;
+#ifndef USE_OLD_SOCKADDR
+ ((struct sockaddr_in *) hostmask)->sin_len =
+ sizeof(struct in_addr);
+#endif
+ memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr,
+ 0xff, sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) hostmask)->sin6_family = AF_INET6;
+#ifndef USE_OLD_SOCKADDR
+ ((struct sockaddr_in6 *) hostmask)->sin6_len =
+ sizeof(struct in6_addr);
+#endif
+ memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr,
+ 0xff, sizeof(struct in6_addr));
+ break;
+ }
+
+ /* Ingress flows, handling SA bundles. */
+ while (TAILQ_NEXT(proto, link)) {
+ error = pf_key_v2_flow(dst, hostmask, src, hostmask, 0, 0, 0,
+ proto->spi[1], proto->proto, src, dst,
+ 0, 1, 0, 0, 0, 0, 0, 0, proto->data);
+ if (error)
+ goto cleanup;
+ proto = TAILQ_NEXT(proto, link);
+ }
+#endif /* SADB_X_EXT_FLOW_TYPE */
+
+ error = pf_key_v2_flow(isa->dst_net, isa->dst_mask, isa->src_net,
+ isa->src_mask, isa->tproto, isa->dport, isa->sport,
+ proto->spi[1], proto->proto, src, dst, 0, 1,
+ sidtype, sid, sidlen, didtype, did, didlen,
+ proto->data);
+
+cleanup:
+#if defined (SADB_X_EXT_FLOW_TYPE)
+ if (sid)
+ free(sid);
+ if (did)
+ free(did);
+#endif /* SADB_X_EXT_FLOW_TYPE */
+
+ return error;
+}
+
+#if defined (SADB_X_ASKPOLICY)
+/* Increase reference count of refcounted sections. */
+static int
+pf_key_v2_conf_refinc(int af, char *section)
+{
+ char conn[22];
+ int num;
+
+ if (!section)
+ return 0;
+
+ num = conf_get_num(section, "Refcount", 0);
+ if (num == 0)
+ return 0;
+
+ snprintf(conn, sizeof conn, "%d", num + 1);
+ conf_set(af, section, "Refcount", conn, 1, 0);
+ return 0;
+}
+#endif
+
+/*
+ * Return 0 if the section didn't exist or was removed, non-zero otherwise.
+ * Don't touch non-refcounted (statically defined) sections.
+ */
+static int
+pf_key_v2_conf_refhandle(int af, char *section)
+{
+ char conn[22];
+ int num;
+
+ if (!section)
+ return 0;
+
+ num = conf_get_num(section, "Refcount", 0);
+ if (num == 1) {
+ conf_remove_section(af, section);
+ num--;
+ } else if (num != 0) {
+ snprintf(conn, sizeof conn, "%d", num - 1);
+ conf_set(af, section, "Refcount", conn, 1, 0);
+ }
+ return num;
+}
+
+/* Remove all dynamically-established configuration entries. */
+static int
+pf_key_v2_remove_conf(char *section)
+{
+ char *ikepeer, *localid, *remoteid, *configname;
+ struct conf_list_node *attr;
+ struct conf_list *attrs;
+ int af;
+
+ if (!section)
+ return 0;
+
+ if (!conf_get_str(section, "Phase"))
+ return 0;
+
+ /* Only remove dynamically-established entries. */
+ attrs = conf_get_list(section, "Flags");
+ if (attrs) {
+ for (attr = TAILQ_FIRST(&attrs->fields); attr;
+ attr = TAILQ_NEXT(attr, link))
+ if (!strcasecmp(attr->field, "__ondemand"))
+ goto passed;
+
+ conf_free_list(attrs);
+ }
+ return 0;
+
+passed:
+ conf_free_list(attrs);
+
+ af = conf_begin();
+
+ configname = conf_get_str(section, "Configuration");
+ conf_remove_section(af, configname);
+
+ /* These are the Phase 2 Local/Remote IDs. */
+ localid = conf_get_str(section, "Local-ID");
+ pf_key_v2_conf_refhandle(af, localid);
+
+ remoteid = conf_get_str(section, "Remote-ID");
+ pf_key_v2_conf_refhandle(af, remoteid);
+
+ ikepeer = conf_get_str(section, "ISAKMP-peer");
+
+ pf_key_v2_conf_refhandle(af, section);
+
+ if (ikepeer) {
+ remoteid = conf_get_str(ikepeer, "Remote-ID");
+ localid = conf_get_str(ikepeer, "ID");
+ configname = conf_get_str(ikepeer, "Configuration");
+
+ pf_key_v2_conf_refhandle(af, ikepeer);
+ pf_key_v2_conf_refhandle(af, configname);
+
+ /* Phase 1 IDs */
+ pf_key_v2_conf_refhandle(af, localid);
+ pf_key_v2_conf_refhandle(af, remoteid);
+ }
+ conf_end(af, 1);
+ return 0;
+}
+
+/* Disable a flow given a SA. */
+static int
+pf_key_v2_disable_sa(struct sa *sa, int incoming)
+{
+ struct ipsec_sa *isa = sa->data;
+ struct sockaddr *dst, *src;
+ struct proto *proto = TAILQ_FIRST(&sa->protos);
+#if !defined (SADB_X_EXT_FLOW_TYPE)
+ struct sockaddr_storage hostmask_storage;
+ struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage;
+ int error;
+#endif /* SADB_X_EXT_FLOW_TYPE */
+
+ sa->transport->vtbl->get_dst(sa->transport, &dst);
+ sa->transport->vtbl->get_src(sa->transport, &src);
+
+ if (!incoming)
+ return pf_key_v2_flow(isa->src_net, isa->src_mask,
+ isa->dst_net, isa->dst_mask, isa->tproto, isa->sport,
+ isa->dport, proto->spi[0], proto->proto, src, dst, 1, 0,
+ 0, 0, 0, 0, 0, 0, proto->data);
+ else {
+#if !defined (SADB_X_EXT_FLOW_TYPE)
+ /* Set hostmask to '-1'. */
+ switch (dst->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) hostmask)->sin_family =
+ AF_INET;
+#ifndef USE_OLD_SOCKADDR
+ ((struct sockaddr_in *) hostmask)->sin_len =
+ sizeof(struct in_addr);
+#endif
+ memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr,
+ 0xff, sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) hostmask)->sin6_family =
+ AF_INET6;
+#ifndef USE_OLD_SOCKADDR
+ ((struct sockaddr_in6 *) hostmask)->sin6_len =
+ sizeof(struct in6_addr);
+#endif
+ memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr,
+ 0xff, sizeof(struct in6_addr));
+ break;
+ }
+
+ /* Ingress flow --- SA bundles */
+ while (TAILQ_NEXT(proto, link)) {
+ error = pf_key_v2_flow(dst, hostmask, src, hostmask,
+ 0, 0, 0, proto->spi[1], proto->proto, src, dst,
+ 1, 1, 0, 0, 0, 0, 0, 0, proto->data);
+ if (error)
+ return error;
+ proto = TAILQ_NEXT(proto, link);
+ }
+#endif /* SADB_X_EXT_FLOW_TYPE */
+
+ return pf_key_v2_flow(isa->dst_net, isa->dst_mask,
+ isa->src_net, isa->src_mask, isa->tproto, isa->dport,
+ isa->sport, proto->spi[1], proto->proto, src, dst, 1, 1,
+ 0, 0, 0, 0, 0, 0, proto->data);
+ }
+}
+
+/*
+ * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO
+ * of the IKE security association SA. Also delete potential flows tied to it.
+ */
+int
+pf_key_v2_delete_spi(struct sa *sa, struct proto *proto, int incoming)
+{
+ struct sadb_msg msg;
+ struct sadb_sa ssa;
+ struct sadb_address *addr = 0;
+ struct sockaddr *saddr;
+ int len, err;
+ struct pf_key_v2_msg *delete = 0, *ret = 0;
+#ifdef KAME
+ struct sadb_x_sa2 ssa2;
+#endif
+
+ /* If it's not an established SA, don't proceed. */
+ if (!(sa->flags & SA_FLAG_READY))
+ return 0;
+
+ /*
+ * If the SA was not replaced and was not one acquired through the
+ * kernel (ACQUIRE message), remove the flow associated with it.
+ * We ignore any errors from the disabling of the flow.
+ */
+ if (!(sa->flags & SA_FLAG_REPLACED)
+ && !(sa->flags & SA_FLAG_ONDEMAND))
+ pf_key_v2_disable_sa(sa, incoming);
+
+ if (sa->name && !(sa->flags & SA_FLAG_REPLACED)) {
+ LOG_DBG((LOG_SYSDEP, 50,
+ "pf_key_v2_delete_spi: removing configuration %s",
+ sa->name));
+ pf_key_v2_remove_conf(sa->name);
+ }
+ msg.sadb_msg_type = SADB_DELETE;
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ break;
+ case IPSEC_PROTO_IPSEC_AH:
+ msg.sadb_msg_satype = SADB_SATYPE_AH;
+ break;
+#if defined (SADB_X_SATYPE_IPCOMP)
+ case IPSEC_PROTO_IPCOMP:
+ msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
+ break;
+#endif
+ default:
+ log_print("pf_key_v2_delete_spi: invalid proto %d",
+ proto->proto);
+ goto cleanup;
+ }
+ msg.sadb_msg_seq = 0;
+ delete = pf_key_v2_msg_new(&msg, 0);
+ if (!delete)
+ goto cleanup;
+
+ /* Setup the SA extension. */
+ ssa.sadb_sa_exttype = SADB_EXT_SA;
+ ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK;
+ memcpy(&ssa.sadb_sa_spi, proto->spi[incoming], sizeof ssa.sadb_sa_spi);
+ ssa.sadb_sa_replay = 0;
+ ssa.sadb_sa_state = 0;
+ ssa.sadb_sa_auth = 0;
+ ssa.sadb_sa_encrypt = 0;
+ ssa.sadb_sa_flags = 0;
+ if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa, 0) == -1)
+ goto cleanup;
+
+#ifdef KAME
+ memset(&ssa2, 0, sizeof ssa2);
+ ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;
+ ssa2.sadb_x_sa2_mode = 0;
+ if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa2, 0) == -1)
+ goto cleanup;
+#endif
+
+ /*
+ * Setup the ADDRESS extensions.
+ */
+ if (incoming)
+ sa->transport->vtbl->get_dst(sa->transport, &saddr);
+ else
+ sa->transport->vtbl->get_src(sa->transport, &saddr);
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, saddr, sysdep_sa_len(saddr));
+ switch (saddr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
+ break;
+ }
+ if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ if (incoming)
+ sa->transport->vtbl->get_src(sa->transport, &saddr);
+ else
+ sa->transport->vtbl->get_dst(sa->transport, &saddr);
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, saddr, sysdep_sa_len(saddr));
+ switch (saddr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
+ break;
+ }
+ if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ ret = pf_key_v2_call(delete);
+ pf_key_v2_msg_free(delete);
+ delete = 0;
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (err) {
+ LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_delete_spi: DELETE: %s",
+ strerror(err)));
+ goto cleanup;
+ }
+ pf_key_v2_msg_free(ret);
+
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_delete_spi: done"));
+
+ return 0;
+
+cleanup:
+ if (addr)
+ free(addr);
+ if (delete)
+ pf_key_v2_msg_free(delete);
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return -1;
+}
+
+static void
+pf_key_v2_stayalive(struct exchange *exchange, void *vconn, int fail)
+{
+ char *conn = vconn;
+ struct sa *sa;
+
+ /* XXX What if it is phase 1 ? */
+ sa = sa_lookup_by_name(conn, 2);
+ if (sa)
+ sa->flags |= SA_FLAG_STAYALIVE;
+
+ /*
+ * Remove failed configuration entry -- call twice because it is
+ * created with a Refcount of 2.
+ */
+ if (fail && (!exchange || exchange->name)) {
+ pf_key_v2_remove_conf(conn);
+ pf_key_v2_remove_conf(conn);
+ }
+}
+
+/* Check if a connection CONN exists, otherwise establish it. */
+void
+pf_key_v2_connection_check(char *conn)
+{
+ if (!sa_lookup_by_name(conn, 2)) {
+ LOG_DBG((LOG_SYSDEP, 70,
+ "pf_key_v2_connection_check: SA for %s missing", conn));
+ exchange_establish(conn, pf_key_v2_stayalive, conn);
+ } else
+ LOG_DBG((LOG_SYSDEP, 70, "pf_key_v2_connection_check: "
+ "SA for %s exists", conn));
+}
+
+/* Handle a PF_KEY lifetime expiration message PMSG. */
+static void
+pf_key_v2_expire(struct pf_key_v2_msg *pmsg)
+{
+ struct sadb_msg *msg;
+ struct sadb_sa *ssa;
+ struct sadb_address *dst;
+ struct sockaddr *dstaddr;
+ struct sadb_lifetime *life, *lifecurrent;
+ struct sa *sa;
+ struct pf_key_v2_node *lifenode, *ext;
+#ifdef USE_DEBUG
+ char *dst_str;
+#endif
+
+ msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg;
+ ext = pf_key_v2_find_ext(pmsg, SADB_EXT_SA);
+ if (!ext) {
+ log_print("pf_key_v2_expire: no SA extension found");
+ return;
+ }
+ ssa = ext->seg;
+ ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST);
+ if (!ext) {
+ log_print("pf_key_v2_expire: "
+ "no destination address extension found");
+ return;
+ }
+ dst = ext->seg;
+ dstaddr = (struct sockaddr *) (dst + 1);
+ lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_HARD);
+ if (!lifenode)
+ lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_SOFT);
+ if (!lifenode) {
+ log_print("pf_key_v2_expire: no lifetime extension found");
+ return;
+ }
+ life = lifenode->seg;
+
+ lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_CURRENT);
+ if (!lifenode) {
+ log_print("pf_key_v2_expire: "
+ "no current lifetime extension found");
+ return;
+ }
+ lifecurrent = lifenode->seg;
+
+#ifdef USE_DEBUG
+
+ if (sockaddr2text(dstaddr, &dst_str, 0))
+ dst_str = 0;
+
+ LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_expire: "
+ "%s dst %s SPI %x sproto %d",
+ life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? "SOFT"
+ : "HARD", dst_str ? dst_str : "<unknown>",
+ ntohl(ssa->sadb_sa_spi), msg->sadb_msg_satype));
+
+ if (dst_str)
+ free(dst_str);
+
+#endif /* USE_DEBUG */
+
+ /*
+ * Find the IPsec SA. The IPsec stack has two SAs for every IKE SA,
+ * one outgoing and one incoming, we regard expirations for any of
+ * them as an expiration of the full IKE SA. Likewise, in
+ * protection suites consisting of more than one protocol, any
+ * expired individual IPsec stack SA will be seen as an expiration
+ * of the full suite.
+ */
+ switch (msg->sadb_msg_satype) {
+ case SADB_SATYPE_ESP:
+ sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi,
+ IPSEC_PROTO_IPSEC_ESP);
+ break;
+
+ case SADB_SATYPE_AH:
+ sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi,
+ IPSEC_PROTO_IPSEC_AH);
+ break;
+
+#ifdef SADB_X_SATYPE_IPCOMP
+ case SADB_X_SATYPE_IPCOMP:
+ sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi,
+ IPSEC_PROTO_IPCOMP);
+ break;
+#endif
+
+ default:
+ /* XXX Log? */
+ sa = 0;
+ break;
+ }
+
+ /* If the SA is already gone, don't do anything. */
+ if (!sa)
+ return;
+
+ /*
+ * If we got a notification, try to renegotiate the SA -- unless of
+ * course it has already been replaced by another.
+ * Also, ignore SAs that were not dynamically established, or that
+ * did not see any use.
+ */
+ if (!(sa->flags & SA_FLAG_REPLACED) &&
+ (sa->flags & SA_FLAG_ONDEMAND) &&
+ lifecurrent->sadb_lifetime_bytes)
+ exchange_establish(sa->name, 0, 0);
+
+ if (life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_HARD) {
+ /* Remove the old SA, it isn't useful anymore. */
+ sa_free(sa);
+ }
+}
+
+/* Handle a PF_KEY SA ACQUIRE message PMSG. */
+static void
+pf_key_v2_acquire(struct pf_key_v2_msg *pmsg)
+{
+#if defined (SADB_X_ASKPOLICY)
+ struct sadb_msg *msg, askpolicy_msg;
+ struct pf_key_v2_msg *askpolicy = 0, *ret = 0;
+ struct sadb_x_policy policy;
+ struct sadb_address *dst = 0, *src = 0;
+ struct sockaddr *dstaddr, *srcaddr = 0;
+ struct sadb_comb *scmb = 0;
+ struct sadb_prop *sprp = 0;
+ struct sadb_ident *srcident = 0, *dstident = 0;
+ char dstbuf[ADDRESS_MAX], srcbuf[ADDRESS_MAX], *peer = 0,
+ *conn = 0;
+ char confname[120];
+ char *srcid = 0, *dstid = 0, *prefstring = 0;
+ int slen, af, afamily, masklen, buflen;
+ struct sockaddr *smask, *sflow, *dmask, *dflow;
+ struct sadb_protocol *sproto;
+ char ssflow[ADDRESS_MAX], sdflow[ADDRESS_MAX];
+ char sdmask[ADDRESS_MAX], ssmask[ADDRESS_MAX];
+ char *sidtype = 0, *didtype = 0;
+ char lname[100], dname[100], configname[30];
+ int shostflag = 0, dhostflag = 0;
+ struct pf_key_v2_node *ext;
+ struct passwd *pwd = 0;
+ u_int16_t sport = 0, dport = 0;
+ u_int8_t tproto = 0;
+ char tmbuf[sizeof sport * 3 + 1], *xform;
+ int connlen;
+#if defined (SADB_X_CREDTYPE_NONE)
+ struct sadb_x_cred *cred = 0, *sauth = 0;
+#endif
+
+ /* This needs to be dynamically allocated. */
+ connlen = 22;
+ conn = malloc(connlen);
+ if (!conn) {
+ log_error("pf_key_v2_acquire: malloc (%d) failed", connlen);
+ return;
+ }
+ msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg;
+
+ ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST);
+ if (!ext) {
+ log_print("pf_key_v2_acquire: "
+ "no destination address specified");
+ return;
+ }
+ dst = ext->seg;
+
+ ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_SRC);
+ if (ext)
+ src = ext->seg;
+
+ ext = pf_key_v2_find_ext(pmsg, SADB_EXT_PROPOSAL);
+ if (ext) {
+ sprp = ext->seg;
+ scmb = (struct sadb_comb *) (sprp + 1);
+ }
+ ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_SRC);
+ if (ext)
+ srcident = ext->seg;
+
+ ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_DST);
+ if (ext)
+ dstident = ext->seg;
+
+ /* Ask the kernel for the matching policy. */
+ bzero(&askpolicy_msg, sizeof askpolicy_msg);
+ askpolicy_msg.sadb_msg_type = SADB_X_ASKPOLICY;
+ askpolicy = pf_key_v2_msg_new(&askpolicy_msg, 0);
+ if (!askpolicy)
+ goto fail;
+
+ policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ policy.sadb_x_policy_len = sizeof policy / PF_KEY_V2_CHUNK;
+ policy.sadb_x_policy_seq = msg->sadb_msg_seq;
+ if (pf_key_v2_msg_add(askpolicy, (struct sadb_ext *)&policy, 0) == -1)
+ goto fail;
+
+ ret = pf_key_v2_call(askpolicy);
+ if (!ret)
+ goto fail;
+
+ /* Now we have all the information needed. */
+
+ ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_FLOW);
+ if (!ext) {
+ log_print("pf_key_v2_acquire: no source flow extension found");
+ goto fail;
+ }
+ sflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1);
+
+ ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_FLOW);
+ if (!ext) {
+ log_print("pf_key_v2_acquire: "
+ "no destination flow extension found");
+ goto fail;
+ }
+ dflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1);
+ ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_MASK);
+ if (!ext) {
+ log_print("pf_key_v2_acquire: no source mask extension found");
+ goto fail;
+ }
+ smask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1);
+
+ ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_MASK);
+ if (!ext) {
+ log_print("pf_key_v2_acquire: "
+ "no destination mask extension found");
+ goto fail;
+ }
+ dmask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1);
+
+ ext = pf_key_v2_find_ext(ret, SADB_X_EXT_FLOW_TYPE);
+ if (!ext) {
+ log_print("pf_key_v2_acquire: no flow type extension found");
+ goto fail;
+ }
+ sproto = ext->seg;
+ tproto = sproto->sadb_protocol_proto;
+
+#if defined (SADB_X_EXT_LOCAL_CREDENTIALS)
+ ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_CREDENTIALS);
+ if (ext)
+ cred = (struct sadb_x_cred *) ext->seg;
+ else
+ cred = 0;
+#endif
+
+#if defined (SADB_X_EXT_LOCAL_AUTH)
+ ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_AUTH);
+ if (ext)
+ sauth = (struct sadb_x_cred *) ext->seg;
+ else
+ sauth = 0;
+#endif
+
+ bzero(ssflow, sizeof ssflow);
+ bzero(sdflow, sizeof sdflow);
+ bzero(ssmask, sizeof ssmask);
+ bzero(sdmask, sizeof sdmask);
+
+ sidtype = didtype = "IPV4_ADDR_SUBNET"; /* default */
+
+ switch (sflow->sa_family) {
+ case AF_INET:
+ if (inet_ntop(AF_INET,
+ &((struct sockaddr_in *) sflow)->sin_addr, ssflow,
+ ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ sport = ((struct sockaddr_in *) sflow)->sin_port;
+ if (inet_ntop(AF_INET,
+ &((struct sockaddr_in *) dflow)->sin_addr, sdflow,
+ ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ dport = ((struct sockaddr_in *) dflow)->sin_port;
+ if (inet_ntop(AF_INET,
+ &((struct sockaddr_in *) smask)->sin_addr, ssmask,
+ ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ if (inet_ntop(AF_INET,
+ &((struct sockaddr_in *) dmask)->sin_addr, sdmask,
+ ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ if (((struct sockaddr_in *) smask)->sin_addr.s_addr ==
+ INADDR_BROADCAST) {
+ shostflag = 1;
+ sidtype = "IPV4_ADDR";
+ }
+ if (((struct sockaddr_in *) dmask)->sin_addr.s_addr ==
+ INADDR_BROADCAST) {
+ dhostflag = 1;
+ didtype = "IPV4_ADDR";
+ }
+ break;
+
+ case AF_INET6:
+ if (inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *) sflow)->sin6_addr,
+ ssflow, ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ sport = ((struct sockaddr_in6 *) sflow)->sin6_port;
+ if (inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *) dflow)->sin6_addr,
+ sdflow, ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ dport = ((struct sockaddr_in6 *) dflow)->sin6_port;
+ if (inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *) smask)->sin6_addr,
+ ssmask, ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ if (inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *) dmask)->sin6_addr,
+ sdmask, ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ sidtype = didtype = "IPV6_ADDR_SUBNET";
+ if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)smask)->sin6_addr)) {
+ shostflag = 1;
+ sidtype = "IPV6_ADDR";
+ }
+ if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)dmask)->sin6_addr)) {
+ dhostflag = 1;
+ didtype = "IPV6_ADDR";
+ }
+ break;
+ }
+
+ dstaddr = (struct sockaddr *)(dst + 1);
+ bzero(dstbuf, sizeof dstbuf);
+ bzero(srcbuf, sizeof srcbuf);
+
+ if (dstaddr->sa_family == 0) {
+ /*
+ * Destination was not specified in the flow -- can we derive
+ * it?
+ */
+ if (dhostflag == 0) {
+ log_print("pf_key_v2_acquire: "
+ "Cannot determine precise destination");
+ goto fail;
+ }
+ dstaddr = dflow;
+ }
+ switch (dstaddr->sa_family) {
+ case AF_INET:
+ if (inet_ntop(AF_INET,
+ &((struct sockaddr_in *) dstaddr)->sin_addr,
+ dstbuf, ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ LOG_DBG((LOG_SYSDEP, 20,
+ "pf_key_v2_acquire: dst=%s sproto %d", dstbuf,
+ msg->sadb_msg_satype));
+ break;
+
+ case AF_INET6:
+ if (inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *) dstaddr)->sin6_addr,
+ dstbuf, ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: inet_ntop failed");
+ goto fail;
+ }
+ LOG_DBG((LOG_SYSDEP, 20,
+ "pf_key_v2_acquire: dst=%s sproto %d", dstbuf,
+ msg->sadb_msg_satype));
+ break;
+ }
+
+ if (src) {
+ srcaddr = (struct sockaddr *) (src + 1);
+
+ switch (srcaddr->sa_family) {
+ case AF_INET:
+ if (inet_ntop(AF_INET,
+ &((struct sockaddr_in *) srcaddr)->sin_addr,
+ srcbuf, ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: "
+ "inet_ntop failed");
+ goto fail;
+ }
+ break;
+
+ case AF_INET6:
+ if (inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *)srcaddr)->sin6_addr,
+ srcbuf, ADDRESS_MAX) == NULL) {
+ log_print("pf_key_v2_acquire: "
+ "inet_ntop failed");
+ goto fail;
+ }
+ break;
+
+ default:
+ /*
+ * The kernel will pass an all '0' EXT_ADDRESS_SRC if
+ * it wasn't specified for the flow. In that case, do
+ * NOT specify the srcaddr in the Peer-name below
+ */
+ srcbuf[0] = 0;
+ srcaddr = NULL;
+ break;
+ }
+ }
+ /* Insert source ID. */
+ if (srcident) {
+ slen = (srcident->sadb_ident_len * sizeof(u_int64_t))
+ - sizeof(struct sadb_ident);
+ if (((unsigned char *) (srcident + 1))[slen - 1] != '\0') {
+ log_print("pf_key_v2_acquire: "
+ "source identity not NUL-terminated");
+ goto fail;
+ }
+ /* Check for valid type. */
+ switch (srcident->sadb_ident_type) {
+#if defined (SADB_X_IDENTTYPE_CONNECTION)
+ case SADB_X_IDENTTYPE_CONNECTION:
+ /* XXX */
+ break;
+#endif
+
+ case SADB_IDENTTYPE_PREFIX:
+ /* Determine what the address family is. */
+ srcid = memchr(srcident + 1, ':', slen);
+ if (srcid)
+ afamily = AF_INET6;
+ else
+ afamily = AF_INET;
+
+ srcid = memchr(srcident + 1, '/', slen);
+ if (!srcid) {
+ log_print("pf_key_v2_acquire: "
+ "badly formatted PREFIX identity");
+ goto fail;
+ }
+ masklen = atoi(srcid + 1);
+
+ /* XXX We only support host addresses. */
+ if ((afamily == AF_INET6 && masklen != 128)
+ || (afamily == AF_INET && masklen != 32)) {
+ log_print("pf_key_v2_acquire: "
+ "non-host address specified in source "
+ "identity (mask length %d), ignoring "
+ "request", masklen);
+ goto fail;
+ }
+ /*
+ * NUL-terminate the PREFIX string at the separator,
+ * then dup.
+ */
+ *srcid = '\0';
+ slen = strlen((char *) (srcident + 1)) +
+ sizeof "ID:Address/";
+ srcid = malloc(slen);
+ if (!srcid) {
+ log_error("pf_key_v2_acquire: "
+ "malloc (%d) failed", slen);
+ goto fail;
+ }
+ snprintf(srcid, slen, "ID:Address/%s",
+ (char *) (srcident + 1));
+
+ /* Set the section if it doesn't already exist. */
+ af = conf_begin();
+ if (!conf_get_str(srcid, "ID-type")) {
+ if (conf_set(af, srcid, "ID-type",
+ afamily == AF_INET ? "IPV4_ADDR" :
+ "IPV6_ADDR", 1, 0)
+ || conf_set(af, srcid, "Refcount", "1", 1,
+ 0)
+ || conf_set(af, srcid, "Address",
+ (char *) (srcident + 1), 1, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else
+ pf_key_v2_conf_refinc(af, srcid);
+ conf_end(af, 1);
+ break;
+
+ case SADB_IDENTTYPE_FQDN:
+ prefstring = "FQDN";
+ /* Fall through */
+ case SADB_IDENTTYPE_USERFQDN:
+ if (!prefstring) {
+ prefstring = "USER_FQDN";
+
+ /*
+ * Check whether there is a string following
+ * the header; if no, that there is a user ID
+ * (and acquire the login name). If there is
+ * both a string and a user ID, check that
+ * they match.
+ */
+ if ((slen == 0) &&
+ (srcident->sadb_ident_id == 0)) {
+ log_print("pf_key_v2_acquire: "
+ "no user FQDN or ID provided");
+ goto fail;
+ }
+ if (srcident->sadb_ident_id) {
+ pwd =
+ getpwuid(srcident->sadb_ident_id);
+ if (!pwd) {
+ log_error("pf_key_v2_acquire: "
+ "could not acquire "
+ "username from provided "
+ "ID %llu",
+ srcident->sadb_ident_id);
+ goto fail;
+ }
+ if (slen != 0)
+ if (strcmp(pwd->pw_name,
+ (char *) (srcident + 1))
+ != 0) {
+ log_print("pf_key_v2_acquire: "
+ "provided user "
+ "name and ID do "
+ "not match (%s != "
+ "%s)",
+ (char *) (srcident + 1),
+ pwd->pw_name);
+ /*
+ * String has
+ * precedence, per
+ * RFC 2367.
+ */
+ }
+ }
+ }
+ buflen = (slen ? slen : strlen(pwd->pw_name)) +
+ strlen(prefstring) + sizeof "ID:/";
+ srcid = malloc(buflen);
+ if (!srcid) {
+ log_error("pf_key_v2_acquire: "
+ "malloc (%d) failed", buflen);
+ goto fail;
+ }
+ snprintf(srcid, buflen, "ID:%s/", prefstring);
+ if (slen != 0)
+ strlcat(srcid,
+ (char *) (srcident + 1), buflen);
+ else
+ strlcat(srcid, pwd->pw_name, buflen);
+ pwd = 0;
+
+ /* Set the section if it doesn't already exist. */
+ af = conf_begin();
+ if (!conf_get_str(srcid, "ID-type")) {
+ if (conf_set(af, srcid, "ID-type", prefstring,
+ 1, 0)
+ || conf_set(af, srcid, "Refcount", "1", 1,
+ 0)
+ || conf_set(af, srcid, "Name",
+ srcid + sizeof "ID:/" - 1 +
+ strlen(prefstring), 1, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else
+ pf_key_v2_conf_refinc(af, srcid);
+ conf_end(af, 1);
+ break;
+
+ default:
+ LOG_DBG((LOG_SYSDEP, 20,
+ "pf_key_v2_acquire: invalid source ID type %d",
+ srcident->sadb_ident_type));
+ goto fail;
+ }
+
+ LOG_DBG((LOG_SYSDEP, 50,
+ "pf_key_v2_acquire: constructed source ID \"%s\"", srcid));
+ prefstring = 0;
+ }
+ /* Insert destination ID. */
+ if (dstident) {
+ slen = (dstident->sadb_ident_len * sizeof(u_int64_t))
+ - sizeof(struct sadb_ident);
+
+ /* Check for valid type. */
+ switch (dstident->sadb_ident_type) {
+#if defined (SADB_X_IDENTTYPE_CONNECTION)
+ case SADB_X_IDENTTYPE_CONNECTION:
+ /* XXX */
+ break;
+#endif
+
+ case SADB_IDENTTYPE_PREFIX:
+ /* Determine what the address family is. */
+ dstid = memchr(dstident + 1, ':', slen);
+ if (dstid)
+ afamily = AF_INET6;
+ else
+ afamily = AF_INET;
+
+ dstid = memchr(dstident + 1, '/', slen);
+ if (!dstid) {
+ log_print("pf_key_v2_acquire: "
+ "badly formatted PREFIX identity");
+ goto fail;
+ }
+ masklen = atoi(dstid + 1);
+
+ /* XXX We only support host addresses. */
+ if ((afamily == AF_INET6 && masklen != 128)
+ || (afamily == AF_INET && masklen != 32)) {
+ log_print("pf_key_v2_acquire: "
+ "non-host address specified in "
+ "destination identity (mask length %d), "
+ "ignoring request", masklen);
+ goto fail;
+ }
+ /*
+ * NUL-terminate the PREFIX string at the separator,
+ * then dup.
+ */
+ *dstid = '\0';
+ slen = strlen((char *) (dstident + 1)) +
+ sizeof "ID:Address/";
+ dstid = malloc(slen);
+ if (!dstid) {
+ log_error("pf_key_v2_acquire: "
+ "malloc (%d) failed", slen);
+ goto fail;
+ }
+ snprintf(dstid, slen, "ID:Address/%s",
+ (char *) (dstident + 1));
+
+ /* Set the section if it doesn't already exist. */
+ af = conf_begin();
+ if (!conf_get_str(dstid, "ID-type")) {
+ if (conf_set(af, dstid, "ID-type",
+ afamily == AF_INET ? "IPV4_ADDR" :
+ "IPV6_ADDR", 1, 0)
+ || conf_set(af, dstid, "Refcount", "1", 1,
+ 0)
+ || conf_set(af, dstid, "Address",
+ (char *) (dstident + 1), 1, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else
+ pf_key_v2_conf_refinc(af, dstid);
+ conf_end(af, 1);
+ break;
+
+ case SADB_IDENTTYPE_FQDN:
+ prefstring = "FQDN";
+ /* Fall through */
+
+ case SADB_IDENTTYPE_USERFQDN:
+ if (!prefstring) {
+ prefstring = "USER_FQDN";
+
+ /*
+ * Check whether there is a string following
+ * the header; if no, that there is a user ID
+ * (and acquire the login name). If there is
+ * both a string and a user ID, check that
+ * they match.
+ */
+ if (slen == 0 &&
+ dstident->sadb_ident_id == 0) {
+ log_print("pf_key_v2_acquire: "
+ "no user FQDN or ID provided");
+ goto fail;
+ }
+ if (dstident->sadb_ident_id) {
+ pwd = getpwuid(dstident->sadb_ident_id);
+ if (!pwd) {
+ log_error("pf_key_v2_acquire: "
+ "could not acquire "
+ "username from provided "
+ "ID %llu",
+ dstident->sadb_ident_id);
+ goto fail;
+ }
+ if (slen != 0)
+ if (strcmp(pwd->pw_name,
+ (char *) (dstident + 1))
+ != 0) {
+ log_print("pf_key_v2_acquire: "
+ "provided user "
+ "name and ID do "
+ "not match (%s != "
+ "%s)",
+ (char *) (dstident + 1),
+ pwd->pw_name);
+ /*
+ * String has
+ * precedence, per RF
+ * 2367.
+ */
+ }
+ }
+ }
+ buflen = (slen ? slen : strlen(pwd->pw_name)) +
+ strlen(prefstring) + sizeof "ID:/";
+ dstid = malloc(buflen);
+ if (!dstid) {
+ log_error("pf_key_v2_acquire: "
+ "malloc (%d) failed", buflen);
+ goto fail;
+ }
+ snprintf(dstid, buflen, "ID:%s/", prefstring);
+ if (slen != 0)
+ strlcat(dstid, (char *) (dstident + 1),
+ buflen);
+ else
+ strlcat(dstid, pwd->pw_name, buflen);
+ pwd = 0;
+
+ /* Set the section if it doesn't already exist. */
+ af = conf_begin();
+ if (!conf_get_str(dstid, "ID-type")) {
+ if (conf_set(af, dstid, "ID-type", prefstring,
+ 1, 0)
+ || conf_set(af, dstid, "Refcount", "1", 1,
+ 0)
+ || conf_set(af, dstid, "Name",
+ dstid + sizeof "ID:/" - 1 +
+ strlen(prefstring), 1, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else
+ pf_key_v2_conf_refinc(af, dstid);
+ conf_end(af, 1);
+ break;
+
+ default:
+ LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_acquire: "
+ "invalid destination ID type %d",
+ dstident->sadb_ident_type));
+ goto fail;
+ }
+
+ LOG_DBG((LOG_SYSDEP, 50,
+ "pf_key_v2_acquire: constructed destination ID \"%s\"",
+ dstid));
+ }
+ /* Now we've placed the necessary IDs in the configuration space. */
+
+ /* Get a new connection sequence number. */
+ for (;; connection_seq++) {
+ snprintf(conn, connlen, "Connection-%u", connection_seq);
+ snprintf(configname, sizeof configname, "Config-Phase2-%u",
+ connection_seq);
+
+ /* Does it exist ? */
+ if (!conf_get_str(conn, "Phase")
+ && !conf_get_str(configname, "Suites"))
+ break;
+ }
+
+ /*
+ * Set the IPsec connection entry. In particular, the following fields:
+ * - Phase
+ * - ISAKMP-peer
+ * - Local-ID/Remote-ID (if provided)
+ * - Acquire-ID (sequence number of kernel message, e.g., PF_KEYv2)
+ * - Configuration
+ *
+ * Also set the following section:
+ * [Peer-dstaddr(/srcaddr)(-srcid)(/dstid)]
+ * with these fields:
+ * - Phase
+ * - ID (if provided)
+ * - Remote-ID (if provided)
+ * - Local-address (if provided)
+ * - Address
+ * - Configuration (if an entry ISAKMP-configuration-dstaddr(/srcaddr)
+ * exists -- otherwise use the defaults)
+ */
+
+ slen = strlen(dstbuf) + strlen(srcbuf) + (srcid ? strlen(srcid) : 0)
+ + (dstid ? strlen(dstid) : 0) + sizeof "Peer-/-/";
+ peer = malloc(slen);
+ if (!peer)
+ goto fail;
+
+ /*
+ * The various cases:
+ * - Peer-dstaddr
+ * - Peer-dstaddr/srcaddr
+ * - Peer-dstaddr/srcaddr-srcid
+ * - Peer-dstaddr/srcaddr-srcid/dstid
+ * - Peer-dstaddr/srcaddr-/dstid
+ * - Peer-dstaddr-srcid/dstid
+ * - Peer-dstaddr-/dstid
+ * - Peer-dstaddr-srcid
+ */
+ snprintf(peer, slen, "Peer-%s%s%s%s%s%s%s", dstbuf, srcaddr ? "/" : "",
+ srcaddr ? srcbuf : "", srcid ? "-" : "", srcid ? srcid : "",
+ dstid ? (srcid ? "/" : "-/") : "", dstid ? dstid : "");
+
+ /*
+ * Set the IPsec connection section. Refcount is set to 2, because
+ * it will be linked both to the incoming and the outgoing SA.
+ */
+ af = conf_begin();
+ if (conf_set(af, conn, "Phase", "2", 0, 0)
+ || conf_set(af, conn, "Flags", "__ondemand", 0, 0)
+ || conf_set(af, conn, "Refcount", "2", 0, 0)
+ || conf_set(af, conn, "ISAKMP-peer", peer, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ /* Set the sequence number. */
+ snprintf(lname, sizeof lname, "%u", msg->sadb_msg_seq);
+ if (conf_set(af, conn, "Acquire-ID", lname, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ /* Set Phase 2 IDs -- this is the Local-ID section. */
+ snprintf(lname, sizeof lname, "Phase2-ID:%s/%s/%u/%u", ssflow, ssmask,
+ tproto, sport);
+ if (conf_set(af, conn, "Local-ID", lname, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (!conf_get_str(lname, "ID-type")) {
+ if (conf_set(af, lname, "Refcount", "1", 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (shostflag) {
+ if (conf_set(af, lname, "ID-type", sidtype, 0, 0)
+ || conf_set(af, lname, "Address", ssflow, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else {
+ if (conf_set(af, lname, "ID-type", sidtype, 0, 0)
+ || conf_set(af, lname, "Network", ssflow, 0, 0)
+ || conf_set(af, lname, "Netmask", ssmask, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ }
+ if (tproto) {
+ snprintf(tmbuf, sizeof sport * 3 + 1, "%u", tproto);
+ if (conf_set(af, lname, "Protocol", tmbuf, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (sport) {
+ snprintf(tmbuf, sizeof sport * 3 + 1, "%u",
+ ntohs(sport));
+ if (conf_set(af, lname, "Port", tmbuf, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ }
+ }
+ } else
+ pf_key_v2_conf_refinc(af, lname);
+
+ /* Set Remote-ID section. */
+ snprintf(dname, sizeof dname, "Phase2-ID:%s/%s/%u/%u", sdflow, sdmask,
+ tproto, dport);
+ if (conf_set(af, conn, "Remote-ID", dname, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (!conf_get_str(dname, "ID-type")) {
+ if (conf_set(af, dname, "Refcount", "1", 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (dhostflag) {
+ if (conf_set(af, dname, "ID-type", didtype, 0, 0)
+ || conf_set(af, dname, "Address", sdflow, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else {
+ if (conf_set(af, dname, "ID-type", didtype, 0, 0)
+ || conf_set(af, dname, "Network", sdflow, 0, 0)
+ || conf_set(af, dname, "Netmask", sdmask, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ }
+
+ if (tproto) {
+ snprintf(tmbuf, sizeof dport * 3 + 1, "%u", tproto);
+ if (conf_set(af, dname, "Protocol", tmbuf, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (dport) {
+ snprintf(tmbuf, sizeof dport * 3 + 1, "%u",
+ ntohs(dport));
+ if (conf_set(af, dname, "Port", tmbuf, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ }
+ }
+ } else
+ pf_key_v2_conf_refinc(af, dname);
+
+ /*
+ * XXX
+ * We should be using information from the proposal to set this up.
+ * At least, we should make this selectable.
+ */
+
+ /* Phase 2 configuration. */
+ if (conf_set(af, conn, "Configuration", configname, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (conf_set(af, configname, "Exchange_type", "Quick_mode", 0, 0)
+ || conf_set(af, configname, "DOI", "IPSEC", 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (conf_get_str("General", "Default-phase-2-suites")) {
+ if (conf_set(af, configname, "Suites",
+ conf_get_str("General", "Default-phase-2-suites"), 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else {
+ if (conf_set(af, configname, "Suites",
+ "QM-ESP-3DES-SHA-PFS-SUITE", 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ }
+
+ /* Set the ISAKMP-peer section. */
+ if (!conf_get_str(peer, "Phase")) {
+ if (conf_set(af, peer, "Phase", "1", 0, 0)
+ || conf_set(af, peer, "Refcount", "1", 0, 0)
+ || conf_set(af, peer, "Address", dstbuf, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (srcaddr && conf_set(af, peer, "Local-address", srcbuf, 0,
+ 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ snprintf(confname, sizeof confname, "ISAKMP-Configuration-%s",
+ peer);
+ if (conf_set(af, peer, "Configuration", confname, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+#if defined (SADB_X_CREDTYPE_NONE)
+ /* Store any credentials passed to us. */
+ if (cred) {
+ struct cert_handler *handler = 0;
+ void *cert;
+ char num[12], *certprint;
+
+ /* Convert to bytes in-place. */
+ cred->sadb_x_cred_len *= PF_KEY_V2_CHUNK;
+
+ if (cred->sadb_x_cred_len <= sizeof *cred) {
+ log_print("pf_key_v2_acquire: "
+ "zero-length credentials, aborting SA "
+ "acquisition");
+ conf_end(af, 0);
+ goto fail;
+ }
+ switch (cred->sadb_x_cred_type) {
+ case SADB_X_CREDTYPE_X509:
+ snprintf(num, sizeof num, "%d",
+ ISAKMP_CERTENC_X509_SIG);
+ handler = cert_get(ISAKMP_CERTENC_X509_SIG);
+ break;
+ case SADB_X_CREDTYPE_KEYNOTE:
+ snprintf(num, sizeof num, "%d",
+ ISAKMP_CERTENC_KEYNOTE);
+ handler = cert_get(ISAKMP_CERTENC_KEYNOTE);
+ break;
+ default:
+ log_print("pf_key_v2_acquire: "
+ "unknown credential type %d",
+ cred->sadb_x_cred_type);
+ conf_end(af, 0);
+ goto fail;
+ }
+
+ if (!handler) {
+ log_print("pf_key_v2_acquire: "
+ "cert_get (%s) failed", num);
+ conf_end(af, 0);
+ goto fail;
+ }
+ /* Set the credential type as a number. */
+ if (conf_set(af, peer, "Credential_type", num, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ /* Get the certificate. */
+ cert = handler->cert_get((u_int8_t *) (cred + 1),
+ cred->sadb_x_cred_len - sizeof *cred);
+
+ /* Now convert to printable format. */
+ certprint = handler->cert_printable(cert);
+ handler->cert_free(cert);
+ if (!certprint
+ || conf_set(af, peer, "Credentials", certprint, 0,
+ 0)) {
+ if (certprint)
+ free(certprint);
+ conf_end(af, 0);
+ goto fail;
+ }
+ free(certprint);
+ }
+#endif /* SADB_X_CREDTYPE_NONE */
+
+ /* Phase 1 configuration. */
+ if (!conf_get_str(confname, "exchange_type")) {
+#if defined (SADB_X_EXT_LOCAL_AUTH)
+ /*
+ * We may have been provided with authentication
+ * material.
+ */
+ if (sauth) {
+ char *authm;
+
+ /* Convert to bytes in-place. */
+ sauth->sadb_x_cred_len *= PF_KEY_V2_CHUNK;
+
+ switch (sauth->sadb_x_cred_type) {
+ case SADB_X_AUTHTYPE_PASSPHRASE:
+ if (conf_set(af, confname,
+ "Transforms", "3DES-SHA", 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (sauth->sadb_x_cred_len <=
+ sizeof *sauth) {
+ log_print("pf_key_v2_acquire: "
+ "zero-length passphrase, "
+ "aborting SA acquisition");
+ conf_end(af, 0);
+ goto fail;
+ }
+ authm = malloc(sauth->sadb_x_cred_len -
+ sizeof *sauth + 1);
+ if (!authm) {
+ log_error("pf_key_v2_acquire: "
+ "malloc (%lu) failed",
+ sauth->sadb_x_cred_len -
+ (unsigned long) sizeof *sauth + 1);
+ conf_end(af, 0);
+ goto fail;
+ }
+ memcpy(authm, sauth + 1,
+ sauth->sadb_x_cred_len -
+ sizeof *sauth + 1);
+
+ /* Set the passphrase in the peer. */
+ if (conf_set(af, peer,
+ "Authentication", authm, 0, 0)) {
+ free(authm);
+ conf_end(af, 0);
+ goto fail;
+ }
+ free(authm);
+ break;
+
+ case SADB_X_AUTHTYPE_RSA:
+ if (conf_set(af, confname,
+ "Transforms", "3DES-SHA-RSA_SIG",
+ 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ if (sauth->sadb_x_cred_len <=
+ sizeof *sauth) {
+ log_print("pf_key_v2_acquire: "
+ "zero-length RSA key, "
+ "aborting SA acquisition");
+ conf_end(af, 0);
+ goto fail;
+ }
+ authm = key_printable(ISAKMP_KEY_RSA,
+ ISAKMP_KEYTYPE_PRIVATE,
+ (u_int8_t *) sauth + 1,
+ sauth->sadb_x_cred_len -
+ sizeof *sauth);
+ if (!authm) {
+ log_print("pf_key_v2_acquire: "
+ "failed to convert "
+ "private key to printable "
+ "format (size %lu)",
+ sauth->sadb_x_cred_len -
+ (unsigned long) sizeof *sauth);
+ conf_end(af, 0);
+ goto fail;
+ }
+ /*
+ * Set the key in the peer. We don't
+ * use "Authentication" to avoid
+ * potential conflicts with file-based
+ * configurations that use public key
+ * authentication but still specify
+ * an "Authentication" tag (typically
+ * as a remnant of passphrase-based
+ * testing).
+ */
+ if (conf_set(af, peer,
+ "PKAuthentication", authm, 0, 0)) {
+ free(authm);
+ conf_end(af, 0);
+ goto fail;
+ }
+ free(authm);
+ break;
+
+ default:
+ log_print("pf_key_v2_acquire: "
+ "unknown authentication "
+ "material type %d received from "
+ "kernel", sauth->sadb_x_cred_type);
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else /* Fall through */
+#endif /* SADB_X_EXT_LOCAL_AUTH */
+ {
+ xform = conf_get_str(
+ "Default-phase-1-configuration",
+ "Transforms");
+ if (conf_set(af, confname, "Transforms",
+ xform ? xform : "3DES-SHA-RSA_SIG", 0,
+ 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ }
+
+ if (conf_set(af, confname, "Exchange_Type", "ID_PROT",
+ 0, 0)
+ || conf_set(af, confname, "DOI", "IPSEC", 0, 0)
+ || conf_set(af, confname, "Refcount", "1", 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else
+ pf_key_v2_conf_refinc(af, confname);
+
+ /* The ID we should use in Phase 1. */
+ if (srcid && conf_set(af, peer, "ID", srcid, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ /* The ID the other side should use in Phase 1. */
+ if (dstid && conf_set(af, peer, "Remote-ID", dstid, 0, 0)) {
+ conf_end(af, 0);
+ goto fail;
+ }
+ } else
+ pf_key_v2_conf_refinc(af, peer);
+
+ /* All done. */
+ conf_end(af, 1);
+
+ /* Let's rock 'n roll. */
+ pf_key_v2_connection_check(conn);
+ conn = 0;
+
+ /* Fall-through to cleanup. */
+fail:
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ if (askpolicy)
+ pf_key_v2_msg_free(askpolicy);
+ if (srcid)
+ free(srcid);
+ if (dstid)
+ free(dstid);
+ if (peer)
+ free(peer);
+ if (conn)
+ free(conn);
+ return;
+#else
+ /* acquire not supported */
+ return;
+#endif /* SADB_X_ASKPOLICY */
+}
+
+static void
+pf_key_v2_notify(struct pf_key_v2_msg *msg)
+{
+ switch (((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type) {
+ case SADB_EXPIRE:
+ pf_key_v2_expire(msg);
+ break;
+
+ case SADB_ACQUIRE:
+ pf_key_v2_acquire(msg);
+ break;
+
+ default:
+ log_print("pf_key_v2_notify: unexpected message type (%d)",
+ ((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type);
+ }
+ pf_key_v2_msg_free(msg);
+}
+
+void
+pf_key_v2_handler(int fd)
+{
+ struct pf_key_v2_msg *msg;
+#if !defined (LINUX_IPSEC)
+ int n;
+
+ /*
+ * As synchronous read/writes to the socket can have taken place
+ * between the select(2) call of the main loop and this handler, we
+ * need to recheck the readability.
+ */
+ if (ioctl(pf_key_v2_socket, FIONREAD, &n) == -1) {
+ log_error("pf_key_v2_handler: ioctl (%d, FIONREAD, &n) failed",
+ pf_key_v2_socket);
+ return;
+ }
+ if (!n)
+ return;
+#endif /* LINUX_IPSEC */
+
+ msg = pf_key_v2_read(0);
+ if (msg)
+ pf_key_v2_notify(msg);
+}
+
+/*
+ * Group 2 IPsec SAs given by the PROTO1 and PROTO2 protocols of the SA IKE
+ * security association in a chain.
+ * XXX Assumes OpenBSD GRPSPIS extension. Should probably be moved to sysdep.c
+ */
+int
+pf_key_v2_group_spis(struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int incoming)
+{
+#if defined (SADB_X_GRPSPIS)
+ struct sadb_msg msg;
+ struct sadb_sa sa1, sa2;
+ struct sadb_address *addr = 0;
+ struct sadb_protocol protocol;
+ struct pf_key_v2_msg *grpspis = 0, *ret = 0;
+ struct sockaddr *saddr;
+ int err;
+ size_t len;
+#ifdef KAME
+ struct sadb_x_sa2 kamesa2;
+#endif
+
+ msg.sadb_msg_type = SADB_X_GRPSPIS;
+ switch (proto1->proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ msg.sadb_msg_satype = SADB_SATYPE_ESP;
+ break;
+ case IPSEC_PROTO_IPSEC_AH:
+ msg.sadb_msg_satype = SADB_SATYPE_AH;
+ break;
+#if defined (SADB_X_SATYPE_IPCOMP)
+ case IPSEC_PROTO_IPCOMP:
+ msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
+ break;
+#endif
+ default:
+ log_print("pf_key_v2_group_spis: invalid proto %d",
+ proto1->proto);
+ goto cleanup;
+ }
+ msg.sadb_msg_seq = 0;
+ grpspis = pf_key_v2_msg_new(&msg, 0);
+ if (!grpspis)
+ goto cleanup;
+
+ /* Setup the SA extensions. */
+ sa1.sadb_sa_exttype = SADB_EXT_SA;
+ sa1.sadb_sa_len = sizeof sa1 / PF_KEY_V2_CHUNK;
+ memcpy(&sa1.sadb_sa_spi, proto1->spi[incoming],
+ sizeof sa1.sadb_sa_spi);
+ sa1.sadb_sa_replay = 0;
+ sa1.sadb_sa_state = 0;
+ sa1.sadb_sa_auth = 0;
+ sa1.sadb_sa_encrypt = 0;
+ sa1.sadb_sa_flags = 0;
+ if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa1, 0) == -1)
+ goto cleanup;
+
+#ifndef KAME
+ sa2.sadb_sa_exttype = SADB_X_EXT_SA2;
+ sa2.sadb_sa_len = sizeof sa2 / PF_KEY_V2_CHUNK;
+ memcpy(&sa2.sadb_sa_spi, proto2->spi[incoming],
+ sizeof sa2.sadb_sa_spi);
+ sa2.sadb_sa_replay = 0;
+ sa2.sadb_sa_state = 0;
+ sa2.sadb_sa_auth = 0;
+ sa2.sadb_sa_encrypt = 0;
+ sa2.sadb_sa_flags = 0;
+ if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa2, 0) == -1)
+ goto cleanup;
+#else
+ memset(&kamesa2, 0, sizeof kamesa2);
+ kamesa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ kamesa2.sadb_x_sa2_len = sizeof kamesa2 / PF_KEY_V2_CHUNK;
+ kamesa2.sadb_x_sa2_mode = 0;
+ if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&kamesa2, 0) == -1)
+ goto cleanup;
+#endif
+
+ /*
+ * Setup the ADDRESS extensions.
+ */
+ if (incoming)
+ sa->transport->vtbl->get_src(sa->transport, &saddr);
+ else
+ sa->transport->vtbl->get_dst(sa->transport, &saddr);
+ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr));
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, saddr, sysdep_sa_len(saddr));
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ addr = calloc(1, len);
+ if (!addr)
+ goto cleanup;
+ addr->sadb_address_exttype = SADB_X_EXT_DST2;
+ addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
+#ifndef __OpenBSD__
+ addr->sadb_address_proto = 0;
+ addr->sadb_address_prefixlen = 0;
+#endif
+ addr->sadb_address_reserved = 0;
+ memcpy(addr + 1, saddr, sysdep_sa_len(saddr));
+ ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
+ if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ /* Setup the PROTOCOL extension. */
+ protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
+ protocol.sadb_protocol_len = sizeof protocol / PF_KEY_V2_CHUNK;
+ switch (proto2->proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ protocol.sadb_protocol_proto = SADB_SATYPE_ESP;
+ break;
+ case IPSEC_PROTO_IPSEC_AH:
+ protocol.sadb_protocol_proto = SADB_SATYPE_AH;
+ break;
+#if defined (SADB_X_SATYPE_IPCOMP)
+ case IPSEC_PROTO_IPCOMP:
+ protocol.sadb_protocol_proto = SADB_X_SATYPE_IPCOMP;
+ break;
+#endif
+ default:
+ log_print("pf_key_v2_group_spis: invalid proto %d",
+ proto2->proto);
+ goto cleanup;
+ }
+ protocol.sadb_protocol_reserved2 = 0;
+ if (pf_key_v2_msg_add(grpspis,
+ (struct sadb_ext *)&protocol, 0) == -1)
+ goto cleanup;
+
+ ret = pf_key_v2_call(grpspis);
+ pf_key_v2_msg_free(grpspis);
+ grpspis = 0;
+ if (!ret)
+ goto cleanup;
+ err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
+ if (err) {
+ log_print("pf_key_v2_group_spis: GRPSPIS: %s", strerror(err));
+ goto cleanup;
+ }
+ pf_key_v2_msg_free(ret);
+
+ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_group_spis: done"));
+
+ return 0;
+
+cleanup:
+ if (addr)
+ free(addr);
+ if (grpspis)
+ pf_key_v2_msg_free(grpspis);
+ if (ret)
+ pf_key_v2_msg_free(ret);
+ return -1;
+
+#else /* SADB_X_GRPSPIS */
+ log_print("pf_key_v2_group_spis: not supported in pure PF_KEYv2");
+ return -1;
+#endif
+}
diff --git a/keyexchange/isakmpd-20041012/pf_key_v2.h b/keyexchange/isakmpd-20041012/pf_key_v2.h
new file mode 100644
index 0000000..8eaed1a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/pf_key_v2.h
@@ -0,0 +1,61 @@
+/* $OpenBSD: pf_key_v2.h,v 1.12 2004/08/10 15:59:10 ho Exp $ */
+/* $EOM: pf_key_v2.h,v 1.4 2000/12/04 04:46:35 angelos Exp $ */
+
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _PF_KEY_V2_H_
+#define _PF_KEY_V2_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+struct proto;
+struct sa;
+struct sockaddr;
+struct kernel_sa;
+
+extern int pf_key_v2_socket;
+
+extern void pf_key_v2_connection_check(char *);
+extern int pf_key_v2_delete_spi(struct sa *, struct proto *, int);
+extern int pf_key_v2_enable_sa(struct sa *, struct sa *);
+extern int pf_key_v2_enable_spi(in_addr_t, in_addr_t, in_addr_t,
+ in_addr_t, u_int8_t *, u_int8_t, in_addr_t);
+extern struct sa_kinfo *pf_key_v2_get_kernel_sa(u_int8_t *, size_t, u_int8_t,
+ struct sockaddr *);
+extern u_int8_t *pf_key_v2_get_spi(size_t *, u_int8_t, struct sockaddr *,
+ struct sockaddr *, u_int32_t);
+extern int pf_key_v2_group_spis(struct sa *, struct proto *,
+ struct proto *, int);
+extern void pf_key_v2_handler(int);
+extern int pf_key_v2_open(void);
+extern int pf_key_v2_set_spi(struct sa *, struct proto *, int,
+ struct sa *);
+
+#endif /* _PF_KEY_V2_H_ */
diff --git a/keyexchange/isakmpd-20041012/policy.c b/keyexchange/isakmpd-20041012/policy.c
new file mode 100644
index 0000000..279b3a1
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/policy.c
@@ -0,0 +1,2318 @@
+/* $OpenBSD: policy.c,v 1.78 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: policy.c,v 1.49 2000/10/24 13:33:39 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <regex.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <keynote.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <openssl/ssl.h>
+#include <netdb.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "exchange.h"
+#include "ipsec.h"
+#include "isakmp_doi.h"
+#include "sa.h"
+#include "transport.h"
+#include "log.h"
+#include "message.h"
+#include "monitor.h"
+#include "util.h"
+#include "policy.h"
+#include "x509.h"
+
+char **policy_asserts = NULL;
+int ignore_policy = 0;
+int policy_asserts_num = 0;
+struct exchange *policy_exchange = 0;
+struct sa *policy_sa = 0;
+struct sa *policy_isakmp_sa = 0;
+
+static const char hextab[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+/*
+ * Adaptation of Vixie's inet_ntop4 ()
+ */
+static const char *
+my_inet_ntop4(const in_addr_t *src, char *dst, size_t size, int normalize)
+{
+ static const char fmt[] = "%03u.%03u.%03u.%03u";
+ char tmp[sizeof "255.255.255.255"];
+ in_addr_t src2;
+
+ if (normalize)
+ src2 = ntohl(*src);
+ else
+ src2 = *src;
+
+ if (snprintf(tmp, sizeof tmp, fmt, ((u_int8_t *)&src2)[0],
+ ((u_int8_t *)&src2)[1], ((u_int8_t *)&src2)[2],
+ ((u_int8_t *)&src2)[3]) > (int)size) {
+ errno = ENOSPC;
+ return 0;
+ }
+ strlcpy(dst, tmp, size);
+ return dst;
+}
+
+static const char *
+my_inet_ntop6(const unsigned char *src, char *dst, size_t size)
+{
+ static const char fmt[] =
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x";
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
+
+ if (snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3],
+ src[4], src[5], src[6], src[7], src[8], src[9], src[10], src[11],
+ src[12], src[13], src[14], src[15]) > (int)size) {
+ errno = ENOSPC;
+ return 0;
+ }
+ strlcpy(dst, tmp, size);
+ return dst;
+}
+
+char *
+policy_callback(char *name)
+{
+ struct proto *proto;
+
+ u_int8_t *attr, *value, *id, *idlocal, *idremote;
+ size_t id_sz, idlocalsz, idremotesz;
+ struct sockaddr *sin;
+ struct ipsec_exch *ie;
+ struct ipsec_sa *is;
+ size_t i;
+ int fmt, lifetype = 0;
+ in_addr_t net, subnet;
+ u_int16_t len, type;
+ time_t tt;
+ char *addr;
+ static char mytimeofday[15];
+
+ /* We use all these as a cache. */
+#define PMAX 32
+ static char *esp_present, *ah_present, *comp_present;
+ static char *ah_hash_alg, *ah_auth_alg, *esp_auth_alg, *esp_enc_alg;
+ static char *comp_alg, ah_life_kbytes[PMAX], ah_life_seconds[PMAX];
+ static char esp_life_kbytes[PMAX], esp_life_seconds[PMAX];
+ static char comp_life_kbytes[PMAX];
+ static char *ah_ecn, *esp_ecn, *comp_ecn;
+ static char comp_life_seconds[PMAX], *ah_encapsulation;
+ static char *esp_encapsulation, *comp_encapsulation;
+ static char ah_key_length[PMAX], esp_key_length[PMAX];
+ static char ah_key_rounds[PMAX], esp_key_rounds[PMAX];
+ static char comp_dict_size[PMAX], comp_private_alg[PMAX];
+ static char *remote_filter_type, *local_filter_type;
+ static char remote_filter_addr_upper[NI_MAXHOST];
+ static char remote_filter_addr_lower[NI_MAXHOST];
+ static char local_filter_addr_upper[NI_MAXHOST];
+ static char local_filter_addr_lower[NI_MAXHOST];
+ static char ah_group_desc[PMAX], esp_group_desc[PMAX];
+ static char comp_group_desc[PMAX], remote_ike_address[NI_MAXHOST];
+ static char local_ike_address[NI_MAXHOST];
+ static char *remote_id_type, remote_id_addr_upper[NI_MAXHOST];
+ static char *phase_1, remote_id_addr_lower[NI_MAXHOST];
+ static char *remote_id_proto, remote_id_port[PMAX];
+ static char remote_filter_port[PMAX], local_filter_port[PMAX];
+ static char *remote_filter_proto, *local_filter_proto, *pfs;
+ static char *initiator, remote_filter_proto_num[3];
+ static char local_filter_proto_num[3], remote_id_proto_num[3];
+ static char phase1_group[PMAX];
+
+ /* Allocated. */
+ static char *remote_filter = 0, *local_filter = 0, *remote_id = 0;
+
+ static int dirty = 1;
+
+ /* We only need to set dirty at initialization time really. */
+ if (strcmp(name, KEYNOTE_CALLBACK_CLEANUP) == 0
+ || strcmp(name, KEYNOTE_CALLBACK_INITIALIZE) == 0) {
+ esp_present = ah_present = comp_present = pfs = "no";
+ ah_hash_alg = ah_auth_alg = phase_1 = "";
+ esp_auth_alg = esp_enc_alg = comp_alg = ah_encapsulation = "";
+ ah_ecn = esp_ecn = comp_ecn = "no";
+ esp_encapsulation = comp_encapsulation = "";
+ remote_filter_type = "";
+ local_filter_type = remote_id_type = initiator = "";
+ remote_filter_proto = local_filter_proto = "";
+ remote_id_proto = "";
+
+ if (remote_filter != 0) {
+ free(remote_filter);
+ remote_filter = 0;
+ }
+ if (local_filter != 0) {
+ free(local_filter);
+ local_filter = 0;
+ }
+ if (remote_id != 0) {
+ free(remote_id);
+ remote_id = 0;
+ }
+ memset(remote_ike_address, 0, sizeof remote_ike_address);
+ memset(local_ike_address, 0, sizeof local_ike_address);
+ memset(ah_life_kbytes, 0, sizeof ah_life_kbytes);
+ memset(ah_life_seconds, 0, sizeof ah_life_seconds);
+ memset(esp_life_kbytes, 0, sizeof esp_life_kbytes);
+ memset(esp_life_seconds, 0, sizeof esp_life_seconds);
+ memset(comp_life_kbytes, 0, sizeof comp_life_kbytes);
+ memset(comp_life_seconds, 0, sizeof comp_life_seconds);
+ memset(ah_key_length, 0, sizeof ah_key_length);
+ memset(ah_key_rounds, 0, sizeof ah_key_rounds);
+ memset(esp_key_length, 0, sizeof esp_key_length);
+ memset(esp_key_rounds, 0, sizeof esp_key_rounds);
+ memset(comp_dict_size, 0, sizeof comp_dict_size);
+ memset(comp_private_alg, 0, sizeof comp_private_alg);
+ memset(remote_filter_addr_upper, 0,
+ sizeof remote_filter_addr_upper);
+ memset(remote_filter_addr_lower, 0,
+ sizeof remote_filter_addr_lower);
+ memset(local_filter_addr_upper, 0,
+ sizeof local_filter_addr_upper);
+ memset(local_filter_addr_lower, 0,
+ sizeof local_filter_addr_lower);
+ memset(remote_id_addr_upper, 0, sizeof remote_id_addr_upper);
+ memset(remote_id_addr_lower, 0, sizeof remote_id_addr_lower);
+ memset(ah_group_desc, 0, sizeof ah_group_desc);
+ memset(esp_group_desc, 0, sizeof esp_group_desc);
+ memset(remote_id_port, 0, sizeof remote_id_port);
+ memset(remote_filter_port, 0, sizeof remote_filter_port);
+ memset(local_filter_port, 0, sizeof local_filter_port);
+ memset(phase1_group, 0, sizeof phase1_group);
+
+ dirty = 1;
+ return "";
+ }
+ /*
+ * If dirty is set, this is the first request for an attribute, so
+ * populate our value cache.
+ */
+ if (dirty) {
+ ie = policy_exchange->data;
+
+ if (ie->pfs)
+ pfs = "yes";
+
+ is = policy_isakmp_sa->data;
+ snprintf(phase1_group, sizeof phase1_group, "%u",
+ is->group_desc);
+
+ for (proto = TAILQ_FIRST(&policy_sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link)) {
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ ah_present = "yes";
+ switch (proto->id) {
+ case IPSEC_AH_MD5:
+ ah_hash_alg = "md5";
+ break;
+
+ case IPSEC_AH_SHA:
+ ah_hash_alg = "sha";
+ break;
+
+ case IPSEC_AH_RIPEMD:
+ ah_hash_alg = "ripemd";
+ break;
+
+ case IPSEC_AH_SHA2_256:
+ ah_auth_alg = "sha2-256";
+ break;
+
+ case IPSEC_AH_SHA2_384:
+ ah_auth_alg = "sha2-384";
+ break;
+
+ case IPSEC_AH_SHA2_512:
+ ah_auth_alg = "sha2-512";
+ break;
+
+ case IPSEC_AH_DES:
+ ah_hash_alg = "des";
+ break;
+ }
+
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ esp_present = "yes";
+ switch (proto->id) {
+ case IPSEC_ESP_DES_IV64:
+ esp_enc_alg = "des-iv64";
+ break;
+
+ case IPSEC_ESP_DES:
+ esp_enc_alg = "des";
+ break;
+
+ case IPSEC_ESP_3DES:
+ esp_enc_alg = "3des";
+ break;
+
+ case IPSEC_ESP_AES:
+ case IPSEC_ESP_AES_128_CTR:
+ esp_enc_alg = "aes";
+ break;
+
+ case IPSEC_ESP_RC5:
+ esp_enc_alg = "rc5";
+ break;
+
+ case IPSEC_ESP_IDEA:
+ esp_enc_alg = "idea";
+ break;
+
+ case IPSEC_ESP_CAST:
+ esp_enc_alg = "cast";
+ break;
+
+ case IPSEC_ESP_BLOWFISH:
+ esp_enc_alg = "blowfish";
+ break;
+
+ case IPSEC_ESP_3IDEA:
+ esp_enc_alg = "3idea";
+ break;
+
+ case IPSEC_ESP_DES_IV32:
+ esp_enc_alg = "des-iv32";
+ break;
+
+ case IPSEC_ESP_RC4:
+ esp_enc_alg = "rc4";
+ break;
+
+ case IPSEC_ESP_NULL:
+ esp_enc_alg = "null";
+ break;
+ }
+
+ break;
+
+ case IPSEC_PROTO_IPCOMP:
+ comp_present = "yes";
+ switch (proto->id) {
+ case IPSEC_IPCOMP_OUI:
+ comp_alg = "oui";
+ break;
+
+ case IPSEC_IPCOMP_DEFLATE:
+ comp_alg = "deflate";
+ break;
+
+ case IPSEC_IPCOMP_LZS:
+ comp_alg = "lzs";
+ break;
+
+ case IPSEC_IPCOMP_V42BIS:
+ comp_alg = "v42bis";
+ break;
+ }
+
+ break;
+ }
+
+ for (attr = proto->chosen->p +
+ ISAKMP_TRANSFORM_SA_ATTRS_OFF;
+ attr < proto->chosen->p +
+ GET_ISAKMP_GEN_LENGTH(proto->chosen->p);
+ attr = value + len) {
+ if (attr + ISAKMP_ATTR_VALUE_OFF >
+ (proto->chosen->p +
+ GET_ISAKMP_GEN_LENGTH(proto->chosen->p)))
+ return "";
+
+ type = GET_ISAKMP_ATTR_TYPE(attr);
+ fmt = ISAKMP_ATTR_FORMAT(type);
+ type = ISAKMP_ATTR_TYPE(type);
+ value = attr + (fmt ?
+ ISAKMP_ATTR_LENGTH_VALUE_OFF :
+ ISAKMP_ATTR_VALUE_OFF);
+ len = (fmt ? ISAKMP_ATTR_LENGTH_VALUE_LEN :
+ GET_ISAKMP_ATTR_LENGTH_VALUE(attr));
+
+ if (value + len > proto->chosen->p +
+ GET_ISAKMP_GEN_LENGTH(proto->chosen->p))
+ return "";
+
+ switch (type) {
+ case IPSEC_ATTR_SA_LIFE_TYPE:
+ lifetype = decode_16(value);
+ break;
+
+ case IPSEC_ATTR_SA_LIFE_DURATION:
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ if (lifetype == IPSEC_DURATION_SECONDS) {
+ if (len == 2)
+ snprintf(ah_life_seconds, sizeof ah_life_seconds,
+ "%u", decode_16(value));
+ else
+ snprintf(ah_life_seconds, sizeof ah_life_seconds,
+ "%u", decode_32(value));
+ } else {
+ if (len == 2)
+ snprintf(ah_life_kbytes, sizeof ah_life_kbytes,
+ "%u", decode_16(value));
+ else
+ snprintf(ah_life_kbytes, sizeof ah_life_kbytes,
+ "%u", decode_32(value));
+ }
+
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ if (lifetype == IPSEC_DURATION_SECONDS) {
+ if (len == 2)
+ snprintf(esp_life_seconds,
+ sizeof esp_life_seconds, "%u",
+ decode_16(value));
+ else
+ snprintf(esp_life_seconds,
+ sizeof esp_life_seconds, "%u",
+ decode_32(value));
+ } else {
+ if (len == 2)
+ snprintf(esp_life_kbytes,
+ sizeof esp_life_kbytes, "%u",
+ decode_16(value));
+ else
+ snprintf(esp_life_kbytes,
+ sizeof esp_life_kbytes, "%u",
+ decode_32(value));
+ }
+
+ break;
+
+ case IPSEC_PROTO_IPCOMP:
+ if (lifetype == IPSEC_DURATION_SECONDS) {
+ if (len == 2)
+ snprintf(comp_life_seconds,
+ sizeof comp_life_seconds, "%u",
+ decode_16(value));
+ else
+ snprintf(comp_life_seconds,
+ sizeof comp_life_seconds, "%u",
+ decode_32(value));
+ } else {
+ if (len == 2)
+ snprintf(comp_life_kbytes,
+ sizeof comp_life_kbytes, "%u",
+ decode_16(value));
+ else
+ snprintf(comp_life_kbytes,
+ sizeof comp_life_kbytes, "%u",
+ decode_32(value));
+ }
+ break;
+ }
+ break;
+
+ case IPSEC_ATTR_GROUP_DESCRIPTION:
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ snprintf(ah_group_desc,
+ sizeof ah_group_desc, "%u",
+ decode_16(value));
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ snprintf(esp_group_desc,
+ sizeof esp_group_desc, "%u",
+ decode_16(value));
+ break;
+
+ case IPSEC_PROTO_IPCOMP:
+ snprintf(comp_group_desc,
+ sizeof comp_group_desc, "%u",
+ decode_16(value));
+ break;
+ }
+ break;
+
+ case IPSEC_ATTR_ECN_TUNNEL:
+ if (decode_16(value))
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ ah_ecn = "yes";
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ esp_ecn = "yes";
+ break;
+
+ case IPSEC_PROTO_IPCOMP:
+ comp_ecn = "yes";
+ break;
+ }
+
+ case IPSEC_ATTR_ENCAPSULATION_MODE:
+ if (decode_16(value) == IPSEC_ENCAP_TUNNEL)
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ ah_encapsulation = "tunnel";
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ esp_encapsulation = "tunnel";
+ break;
+
+ case IPSEC_PROTO_IPCOMP:
+ comp_encapsulation = "tunnel";
+ break;
+ }
+#if defined (USE_NAT_TRAVERSAL)
+ else if (decode_16(value) ==
+ IPSEC_ENCAP_UDP_ENCAP_TUNNEL ||
+ decode_16(value) ==
+ IPSEC_ENCAP_UDP_ENCAP_TUNNEL_DRAFT)
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ ah_encapsulation = "udp-encap-tunnel";
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ esp_encapsulation = "udp-encap-tunnel";
+ break;
+
+ case IPSEC_PROTO_IPCOMP:
+ comp_encapsulation = "udp-encap-tunnel";
+ break;
+ }
+ /* XXX IPSEC_ENCAP_UDP_ENCAP_TRANSPORT */
+#endif
+ else
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ ah_encapsulation = "transport";
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ esp_encapsulation = "transport";
+ break;
+
+ case IPSEC_PROTO_IPCOMP:
+ comp_encapsulation = "transport";
+ break;
+ }
+ break;
+
+ case IPSEC_ATTR_AUTHENTICATION_ALGORITHM:
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ switch (decode_16(value)) {
+ case IPSEC_AUTH_HMAC_MD5:
+ ah_auth_alg = "hmac-md5";
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA:
+ ah_auth_alg = "hmac-sha";
+ break;
+
+ case IPSEC_AUTH_HMAC_RIPEMD:
+ ah_auth_alg = "hmac-ripemd";
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_256:
+ ah_auth_alg = "hmac-sha2-256";
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_384:
+ ah_auth_alg = "hmac-sha2-384";
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_512:
+ ah_auth_alg = "hmac-sha2-512";
+ break;
+
+ case IPSEC_AUTH_DES_MAC:
+ ah_auth_alg = "des-mac";
+ break;
+
+ case IPSEC_AUTH_KPDK:
+ ah_auth_alg = "kpdk";
+ break;
+ }
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ switch (decode_16(value)) {
+ case IPSEC_AUTH_HMAC_MD5:
+ esp_auth_alg = "hmac-md5";
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA:
+ esp_auth_alg = "hmac-sha";
+ break;
+
+ case IPSEC_AUTH_HMAC_RIPEMD:
+ esp_auth_alg = "hmac-ripemd";
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_256:
+ esp_auth_alg = "hmac-sha2-256";
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_384:
+ esp_auth_alg = "hmac-sha2-384";
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_512:
+ esp_auth_alg = "hmac-sha2-512";
+ break;
+
+ case IPSEC_AUTH_DES_MAC:
+ esp_auth_alg = "des-mac";
+ break;
+
+ case IPSEC_AUTH_KPDK:
+ esp_auth_alg = "kpdk";
+ break;
+ }
+ break;
+ }
+ break;
+
+ case IPSEC_ATTR_KEY_LENGTH:
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ snprintf(ah_key_length,
+ sizeof ah_key_length, "%u",
+ decode_16(value));
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ snprintf(esp_key_length,
+ sizeof esp_key_length, "%u",
+ decode_16(value));
+ break;
+ }
+ break;
+
+ case IPSEC_ATTR_KEY_ROUNDS:
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_AH:
+ snprintf(ah_key_rounds,
+ sizeof ah_key_rounds, "%u",
+ decode_16(value));
+ break;
+
+ case IPSEC_PROTO_IPSEC_ESP:
+ snprintf(esp_key_rounds,
+ sizeof esp_key_rounds, "%u",
+ decode_16(value));
+ break;
+ }
+ break;
+
+ case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE:
+ snprintf(comp_dict_size,
+ sizeof comp_dict_size, "%u",
+ decode_16(value));
+ break;
+
+ case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM:
+ snprintf(comp_private_alg,
+ sizeof comp_private_alg, "%u",
+ decode_16(value));
+ break;
+ }
+ }
+ }
+
+ policy_sa->transport->vtbl->get_src(policy_sa->transport,
+ &sin);
+ if (sockaddr2text(sin, &addr, 1)) {
+ log_error("policy_callback: sockaddr2text failed");
+ goto bad;
+ }
+ strlcpy(local_ike_address, addr, sizeof local_ike_address);
+ free(addr);
+
+ policy_sa->transport->vtbl->get_dst(policy_sa->transport,
+ &sin);
+ if (sockaddr2text(sin, &addr, 1)) {
+ log_error("policy_callback: sockaddr2text failed");
+ goto bad;
+ }
+ strlcpy(remote_ike_address, addr, sizeof remote_ike_address);
+ free(addr);
+
+ switch (policy_isakmp_sa->exch_type) {
+ case ISAKMP_EXCH_AGGRESSIVE:
+ phase_1 = "aggressive";
+ break;
+
+ case ISAKMP_EXCH_ID_PROT:
+ phase_1 = "main";
+ break;
+ }
+
+ if (policy_isakmp_sa->initiator) {
+ id = policy_isakmp_sa->id_r;
+ id_sz = policy_isakmp_sa->id_r_len;
+ } else {
+ id = policy_isakmp_sa->id_i;
+ id_sz = policy_isakmp_sa->id_i_len;
+ }
+
+ switch (id[0]) {
+ case IPSEC_ID_IPV4_ADDR:
+ remote_id_type = "IPv4 address";
+
+ net = decode_32(id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ);
+ my_inet_ntop4(&net, remote_id_addr_upper,
+ sizeof remote_id_addr_upper - 1, 1);
+ my_inet_ntop4(&net, remote_id_addr_lower,
+ sizeof remote_id_addr_lower - 1, 1);
+ remote_id = strdup(remote_id_addr_upper);
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "strdup (\"%s\") failed",
+ remote_id_addr_upper);
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_IPV4_RANGE:
+ remote_id_type = "IPv4 range";
+
+ net = decode_32(id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ);
+ my_inet_ntop4(&net, remote_id_addr_lower,
+ sizeof remote_id_addr_lower - 1, 1);
+ net = decode_32(id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ + 4);
+ my_inet_ntop4(&net, remote_id_addr_upper,
+ sizeof remote_id_addr_upper - 1, 1);
+ len = strlen(remote_id_addr_upper) +
+ strlen(remote_id_addr_lower) + 2;
+ remote_id = calloc(len, sizeof(char));
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(remote_id, remote_id_addr_lower, len);
+ strlcat(remote_id, "-", len);
+ strlcat(remote_id, remote_id_addr_upper, len);
+ break;
+
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ remote_id_type = "IPv4 subnet";
+
+ net = decode_32(id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ);
+ subnet = decode_32(id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ + 4);
+ net &= subnet;
+ my_inet_ntop4(&net, remote_id_addr_lower,
+ sizeof remote_id_addr_lower - 1, 1);
+ net |= ~subnet;
+ my_inet_ntop4(&net, remote_id_addr_upper,
+ sizeof remote_id_addr_upper - 1, 1);
+ len = strlen(remote_id_addr_upper) +
+ strlen(remote_id_addr_lower) + 2;
+ remote_id = calloc(len, sizeof(char));
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(remote_id, remote_id_addr_lower, len);
+ strlcat(remote_id, "-", len);
+ strlcat(remote_id, remote_id_addr_upper, len);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ remote_id_type = "IPv6 address";
+ my_inet_ntop6(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ remote_id_addr_upper, sizeof remote_id_addr_upper);
+ strlcpy(remote_id_addr_lower, remote_id_addr_upper,
+ sizeof remote_id_addr_lower);
+ remote_id = strdup(remote_id_addr_upper);
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "strdup (\"%s\") failed",
+ remote_id_addr_upper);
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_IPV6_RANGE:
+ remote_id_type = "IPv6 range";
+
+ my_inet_ntop6(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ remote_id_addr_lower,
+ sizeof remote_id_addr_lower - 1);
+
+ my_inet_ntop6(id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ + 16, remote_id_addr_upper,
+ sizeof remote_id_addr_upper - 1);
+
+ len = strlen(remote_id_addr_upper) +
+ strlen(remote_id_addr_lower) + 2;
+ remote_id = calloc(len, sizeof(char));
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(remote_id, remote_id_addr_lower, len);
+ strlcat(remote_id, "-", len);
+ strlcat(remote_id, remote_id_addr_upper, len);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ {
+ struct in6_addr net, mask;
+
+ remote_id_type = "IPv6 subnet";
+
+ bcopy(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, &net,
+ sizeof(net));
+ bcopy(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ + 16,
+ &mask, sizeof(mask));
+
+ for (i = 0; i < 16; i++)
+ net.s6_addr[i] &= mask.s6_addr[i];
+
+ my_inet_ntop6((unsigned char *)&net,
+ remote_id_addr_lower,
+ sizeof remote_id_addr_lower - 1);
+
+ for (i = 0; i < 16; i++)
+ net.s6_addr[i] |= ~mask.s6_addr[i];
+
+ my_inet_ntop6((unsigned char *)&net,
+ remote_id_addr_upper,
+ sizeof remote_id_addr_upper - 1);
+
+ len = strlen(remote_id_addr_upper) +
+ strlen(remote_id_addr_lower) + 2;
+ remote_id = calloc(len, sizeof(char));
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(remote_id, remote_id_addr_lower, len);
+ strlcat(remote_id, "-", len);
+ strlcat(remote_id, remote_id_addr_upper, len);
+ break;
+ }
+
+ case IPSEC_ID_FQDN:
+ remote_id_type = "FQDN";
+ remote_id = calloc(id_sz - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ + 1, sizeof(char));
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "calloc (%lu, %lu) failed",
+ (unsigned long)id_sz - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ + 1,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ memcpy(remote_id,
+ id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
+ break;
+
+ case IPSEC_ID_USER_FQDN:
+ remote_id_type = "User FQDN";
+ remote_id = calloc(id_sz - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ + 1, sizeof(char));
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "calloc (%lu, %lu) failed",
+ (unsigned long)id_sz - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ + 1,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ memcpy(remote_id,
+ id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
+ break;
+
+ case IPSEC_ID_DER_ASN1_DN:
+ remote_id_type = "ASN1 DN";
+
+ remote_id = x509_DN_string(id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ,
+ id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
+ if (!remote_id) {
+ LOG_DBG((LOG_POLICY, 50,
+ "policy_callback: failed to decode name"));
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_DER_ASN1_GN: /* XXX */
+ remote_id_type = "ASN1 GN";
+ break;
+
+ case IPSEC_ID_KEY_ID:
+ remote_id_type = "Key ID";
+ remote_id = calloc(2 * (id_sz - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ) + 1, sizeof(char));
+ if (!remote_id) {
+ log_error("policy_callback: "
+ "calloc (%lu, %lu) failed",
+ 2 * ((unsigned long)id_sz -
+ ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ) + 1,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ /* Does it contain any non-printable characters ? */
+ for (i = 0;
+ i < id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ;
+ i++)
+ if (!isprint(*(id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ + i)))
+ break;
+ if (i >= id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ) {
+ memcpy(remote_id, id + ISAKMP_ID_DATA_OFF -
+ ISAKMP_GEN_SZ,
+ id_sz - ISAKMP_ID_DATA_OFF +
+ ISAKMP_GEN_SZ);
+ break;
+ }
+ /* Non-printable characters, convert to hex */
+ for (i = 0;
+ i < id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ;
+ i++) {
+ remote_id[2 * i] = hextab[*(id +
+ ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ) >> 4];
+ remote_id[2 * i + 1] = hextab[*(id +
+ ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ) & 0xF];
+ }
+ break;
+
+ default:
+ log_print("policy_callback: "
+ "unknown remote ID type %u", id[0]);
+ goto bad;
+ }
+
+ switch (id[1]) {
+ case IPPROTO_TCP:
+ remote_id_proto = "tcp";
+ break;
+
+ case IPPROTO_UDP:
+ remote_id_proto = "udp";
+ break;
+
+#ifdef IPPROTO_ETHERIP
+ case IPPROTO_ETHERIP:
+ remote_id_proto = "etherip";
+ break;
+#endif
+
+ default:
+ snprintf(remote_id_proto_num,
+ sizeof remote_id_proto_num, "%d",
+ id[1]);
+ remote_id_proto = remote_id_proto_num;
+ break;
+ }
+
+ snprintf(remote_id_port, sizeof remote_id_port, "%u",
+ decode_16(id + 2));
+
+ if (policy_exchange->initiator) {
+ initiator = "yes";
+ idlocal = ie->id_ci;
+ idremote = ie->id_cr;
+ idlocalsz = ie->id_ci_sz;
+ idremotesz = ie->id_cr_sz;
+ } else {
+ initiator = "no";
+ idlocal = ie->id_cr;
+ idremote = ie->id_ci;
+ idlocalsz = ie->id_cr_sz;
+ idremotesz = ie->id_ci_sz;
+ }
+
+ /* Initialize the ID variables. */
+ if (idremote) {
+ switch (GET_ISAKMP_ID_TYPE(idremote)) {
+ case IPSEC_ID_IPV4_ADDR:
+ remote_filter_type = "IPv4 address";
+
+ net = decode_32(idremote + ISAKMP_ID_DATA_OFF);
+ my_inet_ntop4(&net, remote_filter_addr_upper,
+ sizeof remote_filter_addr_upper - 1, 1);
+ my_inet_ntop4(&net, remote_filter_addr_lower,
+ sizeof remote_filter_addr_lower - 1, 1);
+ remote_filter =
+ strdup(remote_filter_addr_upper);
+ if (!remote_filter) {
+ log_error("policy_callback: strdup "
+ "(\"%s\") failed",
+ remote_filter_addr_upper);
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_IPV4_RANGE:
+ remote_filter_type = "IPv4 range";
+
+ net = decode_32(idremote + ISAKMP_ID_DATA_OFF);
+ my_inet_ntop4(&net, remote_filter_addr_lower,
+ sizeof remote_filter_addr_lower - 1, 1);
+ net = decode_32(idremote + ISAKMP_ID_DATA_OFF +
+ 4);
+ my_inet_ntop4(&net, remote_filter_addr_upper,
+ sizeof remote_filter_addr_upper - 1, 1);
+ len = strlen(remote_filter_addr_upper) +
+ strlen(remote_filter_addr_lower) + 2;
+ remote_filter = calloc(len, sizeof(char));
+ if (!remote_filter) {
+ log_error("policy_callback: calloc "
+ "(%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(remote_filter,
+ remote_filter_addr_lower, len);
+ strlcat(remote_filter, "-", len);
+ strlcat(remote_filter,
+ remote_filter_addr_upper, len);
+ break;
+
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ remote_filter_type = "IPv4 subnet";
+
+ net = decode_32(idremote + ISAKMP_ID_DATA_OFF);
+ subnet = decode_32(idremote +
+ ISAKMP_ID_DATA_OFF + 4);
+ net &= subnet;
+ my_inet_ntop4(&net, remote_filter_addr_lower,
+ sizeof remote_filter_addr_lower - 1, 1);
+ net |= ~subnet;
+ my_inet_ntop4(&net, remote_filter_addr_upper,
+ sizeof remote_filter_addr_upper - 1, 1);
+ len = strlen(remote_filter_addr_upper) +
+ strlen(remote_filter_addr_lower) + 2;
+ remote_filter = calloc(len, sizeof(char));
+ if (!remote_filter) {
+ log_error("policy_callback: calloc "
+ "(%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(remote_filter,
+ remote_filter_addr_lower, len);
+ strlcat(remote_filter, "-", len);
+ strlcat(remote_filter,
+ remote_filter_addr_upper, len);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ remote_filter_type = "IPv6 address";
+ my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF,
+ remote_filter_addr_upper,
+ sizeof remote_filter_addr_upper - 1);
+ strlcpy(remote_filter_addr_lower,
+ remote_filter_addr_upper,
+ sizeof remote_filter_addr_lower);
+ remote_filter =
+ strdup(remote_filter_addr_upper);
+ if (!remote_filter) {
+ log_error("policy_callback: strdup "
+ "(\"%s\") failed",
+ remote_filter_addr_upper);
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_IPV6_RANGE:
+ remote_filter_type = "IPv6 range";
+
+ my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF,
+ remote_filter_addr_lower,
+ sizeof remote_filter_addr_lower - 1);
+
+ my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF +
+ 16, remote_filter_addr_upper,
+ sizeof remote_filter_addr_upper - 1);
+
+ len = strlen(remote_filter_addr_upper) +
+ strlen(remote_filter_addr_lower) + 2;
+ remote_filter = calloc(len, sizeof(char));
+ if (!remote_filter) {
+ log_error("policy_callback: calloc "
+ "(%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(remote_filter,
+ remote_filter_addr_lower, len);
+ strlcat(remote_filter, "-", len);
+ strlcat(remote_filter,
+ remote_filter_addr_upper, len);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ {
+ struct in6_addr net, mask;
+
+ remote_filter_type = "IPv6 subnet";
+
+ bcopy(idremote + ISAKMP_ID_DATA_OFF,
+ &net, sizeof(net));
+ bcopy(idremote + ISAKMP_ID_DATA_OFF +
+ 16, &mask, sizeof(mask));
+
+ for (i = 0; i < 16; i++)
+ net.s6_addr[i] &=
+ mask.s6_addr[i];
+
+ my_inet_ntop6((unsigned char *)&net,
+ remote_filter_addr_lower,
+ sizeof remote_filter_addr_lower - 1);
+
+ for (i = 0; i < 16; i++)
+ net.s6_addr[i] |=
+ ~mask.s6_addr[i];
+
+ my_inet_ntop6((unsigned char *)&net,
+ remote_filter_addr_upper,
+ sizeof remote_filter_addr_upper - 1);
+
+ len = strlen(remote_filter_addr_upper)
+ + strlen(remote_filter_addr_lower) + 2;
+ remote_filter = calloc(len,
+ sizeof(char));
+ if (!remote_filter) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed",
+ len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(remote_filter,
+ remote_filter_addr_lower, len);
+ strlcat(remote_filter, "-", len);
+ strlcat(remote_filter,
+ remote_filter_addr_upper, len);
+ break;
+ }
+
+ case IPSEC_ID_FQDN:
+ remote_filter_type = "FQDN";
+ remote_filter = malloc(idremotesz -
+ ISAKMP_ID_DATA_OFF + 1);
+ if (!remote_filter) {
+ log_error("policy_callback: "
+ "malloc (%lu) failed",
+ (unsigned long)idremotesz -
+ ISAKMP_ID_DATA_OFF + 1);
+ goto bad;
+ }
+ memcpy(remote_filter,
+ idremote + ISAKMP_ID_DATA_OFF,
+ idremotesz - ISAKMP_ID_DATA_OFF);
+ remote_filter[idremotesz - ISAKMP_ID_DATA_OFF]
+ = '\0';
+ break;
+
+ case IPSEC_ID_USER_FQDN:
+ remote_filter_type = "User FQDN";
+ remote_filter = malloc(idremotesz -
+ ISAKMP_ID_DATA_OFF + 1);
+ if (!remote_filter) {
+ log_error("policy_callback: "
+ "malloc (%lu) failed",
+ (unsigned long)idremotesz -
+ ISAKMP_ID_DATA_OFF + 1);
+ goto bad;
+ }
+ memcpy(remote_filter,
+ idremote + ISAKMP_ID_DATA_OFF,
+ idremotesz - ISAKMP_ID_DATA_OFF);
+ remote_filter[idremotesz - ISAKMP_ID_DATA_OFF]
+ = '\0';
+ break;
+
+ case IPSEC_ID_DER_ASN1_DN:
+ remote_filter_type = "ASN1 DN";
+
+ remote_filter = x509_DN_string(idremote +
+ ISAKMP_ID_DATA_OFF,
+ idremotesz - ISAKMP_ID_DATA_OFF);
+ if (!remote_filter) {
+ LOG_DBG((LOG_POLICY, 50,
+ "policy_callback: "
+ "failed to decode name"));
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_DER_ASN1_GN: /* XXX -- not sure
+ * what's in this. */
+ remote_filter_type = "ASN1 GN";
+ break;
+
+ case IPSEC_ID_KEY_ID:
+ remote_filter_type = "Key ID";
+ remote_filter
+ = calloc(2 * (idremotesz -
+ ISAKMP_ID_DATA_OFF) + 1,
+ sizeof(char));
+ if (!remote_filter) {
+ log_error("policy_callback: "
+ "calloc (%lu, %lu) failed",
+ 2 * ((unsigned long)idremotesz -
+ ISAKMP_ID_DATA_OFF) + 1,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ /*
+ * Does it contain any non-printable
+ * characters ?
+ */
+ for (i = 0;
+ i < idremotesz - ISAKMP_ID_DATA_OFF; i++)
+ if (!isprint(*(idremote +
+ ISAKMP_ID_DATA_OFF + i)))
+ break;
+ if (i >= idremotesz - ISAKMP_ID_DATA_OFF) {
+ memcpy(remote_filter,
+ idremote + ISAKMP_ID_DATA_OFF,
+ idremotesz - ISAKMP_ID_DATA_OFF);
+ break;
+ }
+ /* Non-printable characters, convert to hex */
+ for (i = 0;
+ i < idremotesz - ISAKMP_ID_DATA_OFF;
+ i++) {
+ remote_filter[2 * i]
+ = hextab[*(idremote +
+ ISAKMP_ID_DATA_OFF) >> 4];
+ remote_filter[2 * i + 1]
+ = hextab[*(idremote +
+ ISAKMP_ID_DATA_OFF) & 0xF];
+ }
+ break;
+
+ default:
+ log_print("policy_callback: "
+ "unknown Remote ID type %u",
+ GET_ISAKMP_ID_TYPE(idremote));
+ goto bad;
+ }
+
+ switch (idremote[ISAKMP_GEN_SZ + 1]) {
+ case IPPROTO_TCP:
+ remote_filter_proto = "tcp";
+ break;
+
+ case IPPROTO_UDP:
+ remote_filter_proto = "udp";
+ break;
+
+#ifdef IPPROTO_ETHERIP
+ case IPPROTO_ETHERIP:
+ remote_filter_proto = "etherip";
+ break;
+#endif
+
+ default:
+ snprintf(remote_filter_proto_num,
+ sizeof remote_filter_proto_num, "%d",
+ idremote[ISAKMP_GEN_SZ + 1]);
+ remote_filter_proto = remote_filter_proto_num;
+ break;
+ }
+
+ snprintf(remote_filter_port, sizeof remote_filter_port,
+ "%u", decode_16(idremote + ISAKMP_GEN_SZ + 2));
+ } else {
+ policy_sa->transport->vtbl->get_dst(policy_sa->transport, &sin);
+ switch (sin->sa_family) {
+ case AF_INET:
+ remote_filter_type = "IPv4 address";
+ break;
+ case AF_INET6:
+ remote_filter_type = "IPv6 address";
+ break;
+ default:
+ log_print("policy_callback: "
+ "unsupported protocol family %d",
+ sin->sa_family);
+ goto bad;
+ }
+ if (sockaddr2text(sin, &addr, 1)) {
+ log_error("policy_callback: "
+ "sockaddr2text failed");
+ goto bad;
+ }
+ memcpy(remote_filter_addr_upper, addr,
+ sizeof remote_filter_addr_upper);
+ memcpy(remote_filter_addr_lower, addr,
+ sizeof remote_filter_addr_lower);
+ free(addr);
+ remote_filter = strdup(remote_filter_addr_upper);
+ if (!remote_filter) {
+ log_error("policy_callback: "
+ "strdup (\"%s\") failed",
+ remote_filter_addr_upper);
+ goto bad;
+ }
+ }
+
+ if (idlocal) {
+ switch (GET_ISAKMP_ID_TYPE(idlocal)) {
+ case IPSEC_ID_IPV4_ADDR:
+ local_filter_type = "IPv4 address";
+
+ net = decode_32(idlocal + ISAKMP_ID_DATA_OFF);
+ my_inet_ntop4(&net, local_filter_addr_upper,
+ sizeof local_filter_addr_upper - 1, 1);
+ my_inet_ntop4(&net, local_filter_addr_lower,
+ sizeof local_filter_addr_upper - 1, 1);
+ local_filter = strdup(local_filter_addr_upper);
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "strdup (\"%s\") failed",
+ local_filter_addr_upper);
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_IPV4_RANGE:
+ local_filter_type = "IPv4 range";
+
+ net = decode_32(idlocal + ISAKMP_ID_DATA_OFF);
+ my_inet_ntop4(&net, local_filter_addr_lower,
+ sizeof local_filter_addr_lower - 1, 1);
+ net = decode_32(idlocal + ISAKMP_ID_DATA_OFF +
+ 4);
+ my_inet_ntop4(&net, local_filter_addr_upper,
+ sizeof local_filter_addr_upper - 1, 1);
+ len = strlen(local_filter_addr_upper)
+ + strlen(local_filter_addr_lower) + 2;
+ local_filter = calloc(len, sizeof(char));
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(local_filter, local_filter_addr_lower,
+ len);
+ strlcat(local_filter, "-", len);
+ strlcat(local_filter, local_filter_addr_upper,
+ len);
+ break;
+
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ local_filter_type = "IPv4 subnet";
+
+ net = decode_32(idlocal + ISAKMP_ID_DATA_OFF);
+ subnet = decode_32(idlocal +
+ ISAKMP_ID_DATA_OFF + 4);
+ net &= subnet;
+ my_inet_ntop4(&net, local_filter_addr_lower,
+ sizeof local_filter_addr_lower - 1, 1);
+ net |= ~subnet;
+ my_inet_ntop4(&net, local_filter_addr_upper,
+ sizeof local_filter_addr_upper - 1, 1);
+ len = strlen(local_filter_addr_upper)
+ + strlen(local_filter_addr_lower) + 2;
+ local_filter = calloc(len, sizeof(char));
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(local_filter, local_filter_addr_lower,
+ len);
+ strlcat(local_filter, "-", len);
+ strlcat(local_filter, local_filter_addr_upper,
+ len);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR:
+ local_filter_type = "IPv6 address";
+ my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF,
+ local_filter_addr_upper,
+ sizeof local_filter_addr_upper - 1);
+ strlcpy(local_filter_addr_lower,
+ local_filter_addr_upper,
+ sizeof local_filter_addr_lower);
+ local_filter = strdup(local_filter_addr_upper);
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "strdup (\"%s\") failed",
+ local_filter_addr_upper);
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_IPV6_RANGE:
+ local_filter_type = "IPv6 range";
+
+ my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF,
+ local_filter_addr_lower,
+ sizeof local_filter_addr_lower - 1);
+
+ my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF +
+ 16, local_filter_addr_upper,
+ sizeof local_filter_addr_upper - 1);
+
+ len = strlen(local_filter_addr_upper)
+ + strlen(local_filter_addr_lower) + 2;
+ local_filter = calloc(len, sizeof(char));
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed", len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(local_filter, local_filter_addr_lower,
+ len);
+ strlcat(local_filter, "-", len);
+ strlcat(local_filter, local_filter_addr_upper,
+ len);
+ break;
+
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ {
+ struct in6_addr net, mask;
+
+ local_filter_type = "IPv6 subnet";
+
+ bcopy(idlocal + ISAKMP_ID_DATA_OFF,
+ &net, sizeof(net));
+ bcopy(idlocal + ISAKMP_ID_DATA_OFF +
+ 16, &mask, sizeof(mask));
+
+ for (i = 0; i < 16; i++)
+ net.s6_addr[i] &=
+ mask.s6_addr[i];
+
+ my_inet_ntop6((unsigned char *)&net,
+ local_filter_addr_lower,
+ sizeof local_filter_addr_lower - 1);
+
+ for (i = 0; i < 16; i++)
+ net.s6_addr[i] |=
+ ~mask.s6_addr[i];
+
+ my_inet_ntop6((unsigned char *)&net,
+ local_filter_addr_upper,
+ sizeof local_filter_addr_upper -
+ 1);
+
+ len = strlen(local_filter_addr_upper)
+ + strlen(local_filter_addr_lower)
+ + 2;
+ local_filter = calloc(len,
+ sizeof(char));
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "calloc (%d, %lu) failed",
+ len,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ strlcpy(local_filter,
+ local_filter_addr_lower, len);
+ strlcat(local_filter, "-", len);
+ strlcat(local_filter,
+ local_filter_addr_upper, len);
+ break;
+ }
+
+ case IPSEC_ID_FQDN:
+ local_filter_type = "FQDN";
+ local_filter = malloc(idlocalsz -
+ ISAKMP_ID_DATA_OFF + 1);
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "malloc (%lu) failed",
+ (unsigned long)idlocalsz -
+ ISAKMP_ID_DATA_OFF + 1);
+ goto bad;
+ }
+ memcpy(local_filter,
+ idlocal + ISAKMP_ID_DATA_OFF,
+ idlocalsz - ISAKMP_ID_DATA_OFF);
+ local_filter[idlocalsz - ISAKMP_ID_DATA_OFF]
+ = '\0';
+ break;
+
+ case IPSEC_ID_USER_FQDN:
+ local_filter_type = "User FQDN";
+ local_filter = malloc(idlocalsz -
+ ISAKMP_ID_DATA_OFF + 1);
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "malloc (%lu) failed",
+ (unsigned long)idlocalsz -
+ ISAKMP_ID_DATA_OFF + 1);
+ goto bad;
+ }
+ memcpy(local_filter,
+ idlocal + ISAKMP_ID_DATA_OFF,
+ idlocalsz - ISAKMP_ID_DATA_OFF);
+ local_filter[idlocalsz - ISAKMP_ID_DATA_OFF]
+ = '\0';
+ break;
+
+ case IPSEC_ID_DER_ASN1_DN:
+ local_filter_type = "ASN1 DN";
+
+ local_filter = x509_DN_string(idlocal +
+ ISAKMP_ID_DATA_OFF,
+ idlocalsz - ISAKMP_ID_DATA_OFF);
+ if (!local_filter) {
+ LOG_DBG((LOG_POLICY, 50,
+ "policy_callback: failed to decode"
+ " name"));
+ goto bad;
+ }
+ break;
+
+ case IPSEC_ID_DER_ASN1_GN:
+ /* XXX -- not sure what's in this. */
+ local_filter_type = "ASN1 GN";
+ break;
+
+ case IPSEC_ID_KEY_ID:
+ local_filter_type = "Key ID";
+ local_filter = calloc(2 * (idlocalsz -
+ ISAKMP_ID_DATA_OFF) + 1,
+ sizeof(char));
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "calloc (%lu, %lu) failed",
+ 2 * ((unsigned long)idlocalsz -
+ ISAKMP_ID_DATA_OFF) + 1,
+ (unsigned long)sizeof(char));
+ goto bad;
+ }
+ /*
+ * Does it contain any non-printable
+ * characters ?
+ */
+ for (i = 0;
+ i < idlocalsz - ISAKMP_ID_DATA_OFF; i++)
+ if (!isprint(*(idlocal +
+ ISAKMP_ID_DATA_OFF + i)))
+ break;
+ if (i >= idlocalsz - ISAKMP_ID_DATA_OFF) {
+ memcpy(local_filter, idlocal +
+ ISAKMP_ID_DATA_OFF,
+ idlocalsz - ISAKMP_ID_DATA_OFF);
+ break;
+ }
+ /* Non-printable characters, convert to hex */
+ for (i = 0;
+ i < idlocalsz - ISAKMP_ID_DATA_OFF; i++) {
+ local_filter[2 * i]
+ = hextab[*(idlocal +
+ ISAKMP_ID_DATA_OFF) >> 4];
+ local_filter[2 * i + 1]
+ = hextab[*(idlocal +
+ ISAKMP_ID_DATA_OFF) & 0xF];
+ }
+ break;
+
+ default:
+ log_print("policy_callback: "
+ "unknown Local ID type %u",
+ GET_ISAKMP_ID_TYPE(idlocal));
+ goto bad;
+ }
+
+ switch (idlocal[ISAKMP_GEN_SZ + 1]) {
+ case IPPROTO_TCP:
+ local_filter_proto = "tcp";
+ break;
+
+ case IPPROTO_UDP:
+ local_filter_proto = "udp";
+ break;
+
+#ifdef IPPROTO_ETHERIP
+ case IPPROTO_ETHERIP:
+ local_filter_proto = "etherip";
+ break;
+#endif
+
+ default:
+ snprintf(local_filter_proto_num,
+ sizeof local_filter_proto_num,
+ "%d", idlocal[ISAKMP_GEN_SZ + 1]);
+ local_filter_proto = local_filter_proto_num;
+ break;
+ }
+
+ snprintf(local_filter_port, sizeof local_filter_port,
+ "%u", decode_16(idlocal + ISAKMP_GEN_SZ + 2));
+ } else {
+ policy_sa->transport->vtbl->get_src(policy_sa->transport,
+ (struct sockaddr **)&sin);
+ switch (sin->sa_family) {
+ case AF_INET:
+ local_filter_type = "IPv4 address";
+ break;
+ case AF_INET6:
+ local_filter_type = "IPv6 address";
+ break;
+ default:
+ log_print("policy_callback: "
+ "unsupported protocol family %d",
+ sin->sa_family);
+ goto bad;
+ }
+
+ if (sockaddr2text(sin, &addr, 1)) {
+ log_error("policy_callback: "
+ "sockaddr2text failed");
+ goto bad;
+ }
+ memcpy(local_filter_addr_upper, addr,
+ sizeof local_filter_addr_upper);
+ memcpy(local_filter_addr_lower, addr,
+ sizeof local_filter_addr_lower);
+ free(addr);
+ local_filter = strdup(local_filter_addr_upper);
+ if (!local_filter) {
+ log_error("policy_callback: "
+ "strdup (\"%s\") failed",
+ local_filter_addr_upper);
+ goto bad;
+ }
+ }
+
+ LOG_DBG((LOG_POLICY, 80,
+ "Policy context (action attributes):"));
+ LOG_DBG((LOG_POLICY, 80, "esp_present == %s", esp_present));
+ LOG_DBG((LOG_POLICY, 80, "ah_present == %s", ah_present));
+ LOG_DBG((LOG_POLICY, 80, "comp_present == %s", comp_present));
+ LOG_DBG((LOG_POLICY, 80, "ah_hash_alg == %s", ah_hash_alg));
+ LOG_DBG((LOG_POLICY, 80, "esp_enc_alg == %s", esp_enc_alg));
+ LOG_DBG((LOG_POLICY, 80, "comp_alg == %s", comp_alg));
+ LOG_DBG((LOG_POLICY, 80, "ah_auth_alg == %s", ah_auth_alg));
+ LOG_DBG((LOG_POLICY, 80, "esp_auth_alg == %s", esp_auth_alg));
+ LOG_DBG((LOG_POLICY, 80, "ah_life_seconds == %s",
+ ah_life_seconds));
+ LOG_DBG((LOG_POLICY, 80, "ah_life_kbytes == %s",
+ ah_life_kbytes));
+ LOG_DBG((LOG_POLICY, 80, "esp_life_seconds == %s",
+ esp_life_seconds));
+ LOG_DBG((LOG_POLICY, 80, "esp_life_kbytes == %s",
+ esp_life_kbytes));
+ LOG_DBG((LOG_POLICY, 80, "comp_life_seconds == %s",
+ comp_life_seconds));
+ LOG_DBG((LOG_POLICY, 80, "comp_life_kbytes == %s",
+ comp_life_kbytes));
+ LOG_DBG((LOG_POLICY, 80, "ah_encapsulation == %s",
+ ah_encapsulation));
+ LOG_DBG((LOG_POLICY, 80, "esp_encapsulation == %s",
+ esp_encapsulation));
+ LOG_DBG((LOG_POLICY, 80, "comp_encapsulation == %s",
+ comp_encapsulation));
+ LOG_DBG((LOG_POLICY, 80, "comp_dict_size == %s",
+ comp_dict_size));
+ LOG_DBG((LOG_POLICY, 80, "comp_private_alg == %s",
+ comp_private_alg));
+ LOG_DBG((LOG_POLICY, 80, "ah_key_length == %s",
+ ah_key_length));
+ LOG_DBG((LOG_POLICY, 80, "ah_key_rounds == %s",
+ ah_key_rounds));
+ LOG_DBG((LOG_POLICY, 80, "esp_key_length == %s",
+ esp_key_length));
+ LOG_DBG((LOG_POLICY, 80, "esp_key_rounds == %s",
+ esp_key_rounds));
+ LOG_DBG((LOG_POLICY, 80, "ah_group_desc == %s",
+ ah_group_desc));
+ LOG_DBG((LOG_POLICY, 80, "esp_group_desc == %s",
+ esp_group_desc));
+ LOG_DBG((LOG_POLICY, 80, "comp_group_desc == %s",
+ comp_group_desc));
+ LOG_DBG((LOG_POLICY, 80, "ah_ecn == %s", ah_ecn));
+ LOG_DBG((LOG_POLICY, 80, "esp_ecn == %s", esp_ecn));
+ LOG_DBG((LOG_POLICY, 80, "comp_ecn == %s", comp_ecn));
+ LOG_DBG((LOG_POLICY, 80, "remote_filter_type == %s",
+ remote_filter_type));
+ LOG_DBG((LOG_POLICY, 80, "remote_filter_addr_upper == %s",
+ remote_filter_addr_upper));
+ LOG_DBG((LOG_POLICY, 80, "remote_filter_addr_lower == %s",
+ remote_filter_addr_lower));
+ LOG_DBG((LOG_POLICY, 80, "remote_filter == %s",
+ (remote_filter ? remote_filter : "")));
+ LOG_DBG((LOG_POLICY, 80, "remote_filter_port == %s",
+ remote_filter_port));
+ LOG_DBG((LOG_POLICY, 80, "remote_filter_proto == %s",
+ remote_filter_proto));
+ LOG_DBG((LOG_POLICY, 80, "local_filter_type == %s",
+ local_filter_type));
+ LOG_DBG((LOG_POLICY, 80, "local_filter_addr_upper == %s",
+ local_filter_addr_upper));
+ LOG_DBG((LOG_POLICY, 80, "local_filter_addr_lower == %s",
+ local_filter_addr_lower));
+ LOG_DBG((LOG_POLICY, 80, "local_filter == %s",
+ (local_filter ? local_filter : "")));
+ LOG_DBG((LOG_POLICY, 80, "local_filter_port == %s",
+ local_filter_port));
+ LOG_DBG((LOG_POLICY, 80, "local_filter_proto == %s",
+ local_filter_proto));
+ LOG_DBG((LOG_POLICY, 80, "remote_id_type == %s",
+ remote_id_type));
+ LOG_DBG((LOG_POLICY, 80, "remote_id_addr_upper == %s",
+ remote_id_addr_upper));
+ LOG_DBG((LOG_POLICY, 80, "remote_id_addr_lower == %s",
+ remote_id_addr_lower));
+ LOG_DBG((LOG_POLICY, 80, "remote_id == %s",
+ (remote_id ? remote_id : "")));
+ LOG_DBG((LOG_POLICY, 80, "remote_id_port == %s",
+ remote_id_port));
+ LOG_DBG((LOG_POLICY, 80, "remote_id_proto == %s",
+ remote_id_proto));
+ LOG_DBG((LOG_POLICY, 80, "remote_negotiation_address == %s",
+ remote_ike_address));
+ LOG_DBG((LOG_POLICY, 80, "local_negotiation_address == %s",
+ local_ike_address));
+ LOG_DBG((LOG_POLICY, 80, "pfs == %s", pfs));
+ LOG_DBG((LOG_POLICY, 80, "initiator == %s", initiator));
+ LOG_DBG((LOG_POLICY, 80, "phase1_group_desc == %s",
+ phase1_group));
+
+ /* Unset dirty now. */
+ dirty = 0;
+ }
+ if (strcmp(name, "phase_1") == 0)
+ return phase_1;
+
+ if (strcmp(name, "GMTTimeOfDay") == 0) {
+ tt = time((time_t)NULL);
+ strftime(mytimeofday, 14, "%Y%m%d%H%M%S", gmtime(&tt));
+ return mytimeofday;
+ }
+ if (strcmp(name, "LocalTimeOfDay") == 0) {
+ tt = time((time_t)NULL);
+ strftime(mytimeofday, 14, "%Y%m%d%H%M%S", localtime(&tt));
+ return mytimeofday;
+ }
+ if (strcmp(name, "initiator") == 0)
+ return initiator;
+
+ if (strcmp(name, "pfs") == 0)
+ return pfs;
+
+ if (strcmp(name, "app_domain") == 0)
+ return "IPsec policy";
+
+ if (strcmp(name, "doi") == 0)
+ return "ipsec";
+
+ if (strcmp(name, "esp_present") == 0)
+ return esp_present;
+
+ if (strcmp(name, "ah_present") == 0)
+ return ah_present;
+
+ if (strcmp(name, "comp_present") == 0)
+ return comp_present;
+
+ if (strcmp(name, "ah_hash_alg") == 0)
+ return ah_hash_alg;
+
+ if (strcmp(name, "ah_auth_alg") == 0)
+ return ah_auth_alg;
+
+ if (strcmp(name, "esp_auth_alg") == 0)
+ return esp_auth_alg;
+
+ if (strcmp(name, "esp_enc_alg") == 0)
+ return esp_enc_alg;
+
+ if (strcmp(name, "comp_alg") == 0)
+ return comp_alg;
+
+ if (strcmp(name, "ah_life_kbytes") == 0)
+ return ah_life_kbytes;
+
+ if (strcmp(name, "ah_life_seconds") == 0)
+ return ah_life_seconds;
+
+ if (strcmp(name, "esp_life_kbytes") == 0)
+ return esp_life_kbytes;
+
+ if (strcmp(name, "esp_life_seconds") == 0)
+ return esp_life_seconds;
+
+ if (strcmp(name, "comp_life_kbytes") == 0)
+ return comp_life_kbytes;
+
+ if (strcmp(name, "comp_life_seconds") == 0)
+ return comp_life_seconds;
+
+ if (strcmp(name, "ah_encapsulation") == 0)
+ return ah_encapsulation;
+
+ if (strcmp(name, "esp_encapsulation") == 0)
+ return esp_encapsulation;
+
+ if (strcmp(name, "comp_encapsulation") == 0)
+ return comp_encapsulation;
+
+ if (strcmp(name, "ah_key_length") == 0)
+ return ah_key_length;
+
+ if (strcmp(name, "ah_key_rounds") == 0)
+ return ah_key_rounds;
+
+ if (strcmp(name, "esp_key_length") == 0)
+ return esp_key_length;
+
+ if (strcmp(name, "esp_key_rounds") == 0)
+ return esp_key_rounds;
+
+ if (strcmp(name, "comp_dict_size") == 0)
+ return comp_dict_size;
+
+ if (strcmp(name, "comp_private_alg") == 0)
+ return comp_private_alg;
+
+ if (strcmp(name, "remote_filter_type") == 0)
+ return remote_filter_type;
+
+ if (strcmp(name, "remote_filter") == 0)
+ return (remote_filter ? remote_filter : "");
+
+ if (strcmp(name, "remote_filter_addr_upper") == 0)
+ return remote_filter_addr_upper;
+
+ if (strcmp(name, "remote_filter_addr_lower") == 0)
+ return remote_filter_addr_lower;
+
+ if (strcmp(name, "remote_filter_port") == 0)
+ return remote_filter_port;
+
+ if (strcmp(name, "remote_filter_proto") == 0)
+ return remote_filter_proto;
+
+ if (strcmp(name, "local_filter_type") == 0)
+ return local_filter_type;
+
+ if (strcmp(name, "local_filter") == 0)
+ return (local_filter ? local_filter : "");
+
+ if (strcmp(name, "local_filter_addr_upper") == 0)
+ return local_filter_addr_upper;
+
+ if (strcmp(name, "local_filter_addr_lower") == 0)
+ return local_filter_addr_lower;
+
+ if (strcmp(name, "local_filter_port") == 0)
+ return local_filter_port;
+
+ if (strcmp(name, "local_filter_proto") == 0)
+ return local_filter_proto;
+
+ if (strcmp(name, "remote_ike_address") == 0)
+ return remote_ike_address;
+
+ if (strcmp(name, "remote_negotiation_address") == 0)
+ return remote_ike_address;
+
+ if (strcmp(name, "local_ike_address") == 0)
+ return local_ike_address;
+
+ if (strcmp(name, "local_negotiation_address") == 0)
+ return local_ike_address;
+
+ if (strcmp(name, "remote_id_type") == 0)
+ return remote_id_type;
+
+ if (strcmp(name, "remote_id") == 0)
+ return (remote_id ? remote_id : "");
+
+ if (strcmp(name, "remote_id_addr_upper") == 0)
+ return remote_id_addr_upper;
+
+ if (strcmp(name, "remote_id_addr_lower") == 0)
+ return remote_id_addr_lower;
+
+ if (strcmp(name, "remote_id_port") == 0)
+ return remote_id_port;
+
+ if (strcmp(name, "remote_id_proto") == 0)
+ return remote_id_proto;
+
+ if (strcmp(name, "phase1_group_desc") == 0)
+ return phase1_group;
+
+ if (strcmp(name, "esp_group_desc") == 0)
+ return esp_group_desc;
+
+ if (strcmp(name, "ah_group_desc") == 0)
+ return ah_group_desc;
+
+ if (strcmp(name, "comp_group_desc") == 0)
+ return comp_group_desc;
+
+ if (strcmp(name, "comp_ecn") == 0)
+ return comp_ecn;
+
+ if (strcmp(name, "ah_ecn") == 0)
+ return ah_ecn;
+
+ if (strcmp(name, "esp_ecn") == 0)
+ return esp_ecn;
+
+ return "";
+
+bad:
+ policy_callback(KEYNOTE_CALLBACK_INITIALIZE);
+ return "";
+}
+
+void
+policy_init(void)
+{
+ char *ptr, *policy_file, *use_keynote;
+ char **asserts;
+ size_t sz, len;
+ int fd, i;
+
+ LOG_DBG((LOG_POLICY, 30, "policy_init: initializing"));
+
+ /* Do we want to use the policy modules? */
+ use_keynote = conf_get_str("General", "Use-Keynote");
+ if (ignore_policy ||
+ (use_keynote && strncmp("yes", use_keynote, 3)))
+ return;
+
+ /* Get policy file from configuration. */
+ policy_file = conf_get_str("General", "Policy-file");
+ if (!policy_file)
+ policy_file = CONF_DFLT_POLICY_FILE;
+
+ /* Open policy file. */
+ fd = monitor_open(policy_file, O_RDONLY, 0);
+ if (fd == -1)
+ log_fatal("policy_init: open (\"%s\", O_RDONLY) failed",
+ policy_file);
+
+ /* Check file modes and collect file size */
+ if (check_file_secrecy_fd(fd, policy_file, &sz)) {
+ close(fd);
+ log_fatal("policy_init: cannot read %s", policy_file);
+ }
+
+ /* Allocate memory to keep policies. */
+ ptr = calloc(sz + 1, sizeof(char));
+ if (!ptr)
+ log_fatal("policy_init: calloc (%lu, %lu) failed",
+ (unsigned long)sz + 1, (unsigned long)sizeof(char));
+
+ /* Just in case there are short reads... */
+ for (len = 0; len < sz; len += i) {
+ i = read(fd, ptr + len, sz - len);
+ if (i == -1)
+ log_fatal("policy_init: read (%d, %p, %lu) failed", fd,
+ ptr + len, (unsigned long)(sz - len));
+ }
+
+ /* We're done with this. */
+ close(fd);
+
+ /* Parse buffer, break up into individual policies. */
+ asserts = kn_read_asserts(ptr, sz, &i);
+
+ /* Begone! */
+ free(ptr);
+
+ if (asserts == (char **)NULL)
+ log_print("policy_init: all policies flushed");
+
+ /* Cleanup */
+ if (policy_asserts) {
+ for (fd = 0; fd < policy_asserts_num; fd++)
+ if (policy_asserts && policy_asserts[fd])
+ free(policy_asserts[fd]);
+
+ free(policy_asserts);
+ }
+ policy_asserts = asserts;
+ policy_asserts_num = i;
+}
+
+/* Nothing needed for initialization */
+int
+keynote_cert_init(void)
+{
+ return 1;
+}
+
+/* Just copy and return. */
+void *
+keynote_cert_get(u_int8_t *data, u_int32_t len)
+{
+ char *foo = malloc(len + 1);
+
+ if (foo == NULL)
+ return NULL;
+
+ memcpy(foo, data, len);
+ foo[len] = '\0';
+ return foo;
+}
+
+/*
+ * We just verify the signature on the credentials.
+ * On signature failure, just drop the whole payload.
+ */
+int
+keynote_cert_validate(void *scert)
+{
+ char **foo;
+ int num, i;
+
+ if (scert == NULL)
+ return 0;
+
+ foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num);
+ if (foo == NULL)
+ return 0;
+
+ for (i = 0; i < num; i++) {
+ if (kn_verify_assertion(scert, strlen((char *)scert))
+ != SIGRESULT_TRUE) {
+ for (; i < num; i++)
+ free(foo[i]);
+ free(foo);
+ return 0;
+ }
+ free(foo[i]);
+ }
+
+ free(foo);
+ return 1;
+}
+
+/* Add received credentials. */
+int
+keynote_cert_insert(int sid, void *scert)
+{
+ char **foo;
+ int num;
+
+ if (scert == NULL)
+ return 0;
+
+ foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num);
+ if (foo == NULL)
+ return 0;
+
+ while (num--)
+ kn_add_assertion(sid, foo[num], strlen(foo[num]), 0);
+
+ return 1;
+}
+
+/* Just regular memory free. */
+void
+keynote_cert_free(void *cert)
+{
+ free(cert);
+}
+
+/* Verify that the key given to us is valid. */
+int
+keynote_certreq_validate(u_int8_t *data, u_int32_t len)
+{
+ struct keynote_deckey dc;
+ int err = 1;
+ char *dat;
+
+ dat = calloc(len + 1, sizeof(char));
+ if (!dat) {
+ log_error("keynote_certreq_validate: calloc (%d, %lu) failed",
+ len + 1, (unsigned long)sizeof(char));
+ return 0;
+ }
+ memcpy(dat, data, len);
+
+ if (kn_decode_key(&dc, dat, KEYNOTE_PUBLIC_KEY) != 0)
+ err = 0;
+ else
+ kn_free_key(&dc);
+
+ free(dat);
+
+ return err;
+}
+
+/* Beats me what we should be doing with this. */
+void *
+keynote_certreq_decode(u_int8_t *data, u_int32_t len)
+{
+ /* XXX */
+ return NULL;
+}
+
+void
+keynote_free_aca(void *blob)
+{
+ /* XXX */
+}
+
+int
+keynote_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert,
+ u_int32_t *certlen)
+{
+ char *dirname, *file, *addr_str;
+ struct stat sb;
+ size_t size;
+ int idtype, fd, len;
+
+ if (!id) {
+ log_print("keynote_cert_obtain: ID is missing");
+ return 0;
+ }
+ /* Get type of ID. */
+ idtype = id[0];
+ id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+ id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+
+ dirname = conf_get_str("KeyNote", "Credential-directory");
+ if (!dirname) {
+ LOG_DBG((LOG_POLICY, 30,
+ "keynote_cert_obtain: no Credential-directory"));
+ return 0;
+ }
+ len = strlen(dirname) + strlen(CREDENTIAL_FILE) + 3;
+
+ switch (idtype) {
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV6_ADDR:
+ util_ntoa(&addr_str, idtype == IPSEC_ID_IPV4_ADDR ?
+ AF_INET : AF_INET6, id);
+ if (addr_str == 0)
+ return 0;
+
+ file = calloc(len + strlen(addr_str), sizeof(char));
+ if (file == NULL) {
+ log_error("keynote_cert_obtain: failed to allocate "
+ "%lu bytes", (unsigned long)len +
+ strlen(addr_str));
+ free(addr_str);
+ return 0;
+ }
+ snprintf(file, len + strlen(addr_str), "%s/%s/%s", dirname,
+ addr_str, CREDENTIAL_FILE);
+ free(addr_str);
+ break;
+
+ case IPSEC_ID_FQDN:
+ case IPSEC_ID_USER_FQDN: {
+ file = calloc(len + id_len, sizeof(char));
+ if (file == NULL) {
+ log_error("keynote_cert_obtain: "
+ "failed to allocate %lu bytes",
+ (unsigned long)len + id_len);
+ return 0;
+ }
+ snprintf(file, len + id_len, "%s/", dirname);
+ memcpy(file + strlen(dirname) + 1, id, id_len);
+ snprintf(file + strlen(dirname) + 1 + id_len,
+ len - strlen(dirname) - 1, "/%s", CREDENTIAL_FILE);
+ break;
+ }
+
+ default:
+ return 0;
+ }
+
+ fd = monitor_open(file, O_RDONLY, 0);
+ if (fd < 0) {
+ LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: "
+ "failed to open \"%s\"", file));
+ free(file);
+ return 0;
+ }
+
+ if (fstat(fd, &sb) < 0) {
+ LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: "
+ "failed to stat \"%s\"", file));
+ free(file);
+ close(fd);
+ return 0;
+ }
+ size = (size_t)sb.st_size;
+
+ *cert = calloc(size + 1, sizeof(char));
+ if (*cert == NULL) {
+ log_error("keynote_cert_obtain: failed to allocate %lu bytes",
+ (unsigned long)size);
+ free(file);
+ return 0;
+ }
+
+ if (read(fd, *cert, size) != (int)size) {
+ LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: "
+ "failed to read %lu bytes from \"%s\"",
+ (unsigned long)size, file));
+ free(file);
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ free(file);
+ *certlen = size;
+ return 1;
+}
+
+/* This should never be called. */
+int
+keynote_cert_get_subjects(void *scert, int *n, u_int8_t ***id,
+ u_int32_t **id_len)
+{
+ return 0;
+}
+
+/* Get the authorizer key. */
+int
+keynote_cert_get_key(void *scert, void *keyp)
+{
+ struct keynote_keylist *kl;
+ int sid, kid, num;
+ char **foo;
+
+ foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num);
+ if (foo == NULL || num == 0) {
+ log_print("keynote_cert_get_key: "
+ "failed to decompose credentials");
+ return 0;
+ }
+ kid = kn_init();
+ if (kid == -1) {
+ log_print("keynote_cert_get_key: "
+ "failed to initialize new policy session");
+ while (num--)
+ free(foo[num]);
+ free(foo);
+ return 0;
+ }
+ sid = kn_add_assertion(kid, foo[num - 1], strlen(foo[num - 1]), 0);
+ while (num--)
+ free(foo[num]);
+ free(foo);
+
+ if (sid == -1) {
+ log_print("keynote_cert_get_key: failed to add assertion");
+ kn_close(kid);
+ return 0;
+ }
+ *(RSA **)keyp = NULL;
+
+ kl = kn_get_licensees(kid, sid);
+ while (kl) {
+ if (kl->key_alg == KEYNOTE_ALGORITHM_RSA ||
+ kl->key_alg == KEYNOTE_ALGORITHM_X509) {
+ *(RSA **)keyp = RSAPublicKey_dup(kl->key_key);
+ break;
+ }
+ kl = kl->key_next;
+ }
+
+ kn_remove_assertion(kid, sid);
+ kn_close(kid);
+ return *(RSA **)keyp == NULL ? 0 : 1;
+}
+
+void *
+keynote_cert_dup(void *cert)
+{
+ return strdup((char *)cert);
+}
+
+void
+keynote_serialize(void *cert, u_int8_t **data, u_int32_t *datalen)
+{
+ *datalen = strlen((char *)cert) + 1;
+ *data = (u_int8_t *)strdup(cert); /* i.e an extra character at
+ * the end... */
+ if (*data == NULL)
+ log_error("keynote_serialize: malloc (%d) failed", *datalen);
+}
+
+/* From cert to printable */
+char *
+keynote_printable(void *cert)
+{
+ return strdup((char *)cert);
+}
+
+/* From printable to cert */
+void *
+keynote_from_printable(char *cert)
+{
+ return strdup(cert);
+}
diff --git a/keyexchange/isakmpd-20041012/policy.h b/keyexchange/isakmpd-20041012/policy.h
new file mode 100644
index 0000000..e4b5e9a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/policy.h
@@ -0,0 +1,70 @@
+/* $OpenBSD: policy.h,v 1.15 2004/06/25 20:25:34 hshoexer Exp $ */
+/* $EOM: policy.h,v 1.12 2000/09/28 12:53:27 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2000 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _POLICY_H_
+#define _POLICY_H_
+
+#if defined (USE_KEYNOTE)
+#define CREDENTIAL_FILE "credentials"
+#define PRIVATE_KEY_FILE "private_key"
+#endif
+
+extern int ignore_policy;
+extern int policy_asserts_num;
+extern int x509_policy_asserts_num;
+extern int x509_policy_asserts_num_alloc;
+extern char **policy_asserts;
+extern char **x509_policy_asserts;
+extern struct exchange *policy_exchange;
+extern struct sa *policy_sa;
+extern struct sa *policy_isakmp_sa;
+
+extern void policy_init(void);
+extern char *policy_callback(char *);
+extern int keynote_cert_init(void);
+extern void *keynote_cert_get(u_int8_t *, u_int32_t);
+extern int keynote_cert_validate(void *);
+extern int keynote_cert_insert(int, void *);
+extern void keynote_cert_free(void *);
+extern int keynote_certreq_validate(u_int8_t *, u_int32_t);
+extern void *keynote_certreq_decode(u_int8_t *, u_int32_t);
+extern void keynote_free_aca(void *);
+extern int keynote_cert_obtain(u_int8_t *, size_t, void *,
+ u_int8_t **, u_int32_t *);
+extern int keynote_cert_get_subjects(void *, int *, u_int8_t ***,
+ u_int32_t **);
+extern int keynote_cert_get_key(void *, void *);
+extern void *keynote_cert_dup(void *);
+extern void keynote_serialize(void *, u_int8_t **, u_int32_t *);
+extern char *keynote_printable(void *);
+extern void *keynote_from_printable(char *);
+#endif /* _POLICY_H_ */
diff --git a/keyexchange/isakmpd-20041012/prf.c b/keyexchange/isakmpd-20041012/prf.c
new file mode 100644
index 0000000..fdb91fe
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/prf.c
@@ -0,0 +1,161 @@
+/* $OpenBSD: prf.c,v 1.14 2004/05/23 18:17:56 hshoexer Exp $ */
+/* $EOM: prf.c,v 1.7 1999/05/02 12:50:29 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "hash.h"
+#include "log.h"
+#include "prf.h"
+
+void prf_hash_init(struct prf_hash_ctx *);
+void prf_hash_update(struct prf_hash_ctx *, unsigned char *, unsigned int);
+void prf_hash_final(unsigned char *, struct prf_hash_ctx *);
+
+/* PRF behaves likes a hash */
+
+void
+prf_hash_init(struct prf_hash_ctx *ctx)
+{
+ memcpy(ctx->hash->ctx, ctx->ctx, ctx->hash->ctxsize);
+ memcpy(ctx->hash->ctx2, ctx->ctx2, ctx->hash->ctxsize);
+}
+
+void
+prf_hash_update(struct prf_hash_ctx *ctx, unsigned char *data,
+ unsigned int len)
+{
+ ctx->hash->Update(ctx->hash->ctx, data, len);
+}
+
+void
+prf_hash_final(unsigned char *digest, struct prf_hash_ctx *ctx)
+{
+ ctx->hash->HMACFinal(digest, ctx->hash);
+}
+
+/*
+ * Obtain a Pseudo-Random Function for us. At the moment this is
+ * the HMAC version of a hash. See RFC-2104 for reference.
+ */
+struct prf *
+prf_alloc(enum prfs type, int subtype, unsigned char *shared,
+ unsigned int sharedsize)
+{
+ struct hash *hash;
+ struct prf *prf;
+ struct prf_hash_ctx *prfctx;
+
+ switch (type) {
+ case PRF_HMAC:
+ hash = hash_get(subtype);
+ if (!hash) {
+ log_print("prf_alloc: unknown hash type %d", subtype);
+ return 0;
+ }
+ break;
+ default:
+ log_print("prf_alloc: unknown PRF type %d", type);
+ return 0;
+ }
+
+ prf = malloc(sizeof *prf);
+ if (!prf) {
+ log_error("prf_alloc: malloc (%lu) failed",
+ (unsigned long)sizeof *prf);
+ return 0;
+ }
+ if (type == PRF_HMAC) {
+ /* Obtain needed memory. */
+ prfctx = malloc(sizeof *prfctx);
+ if (!prfctx) {
+ log_error("prf_alloc: malloc (%lu) failed",
+ (unsigned long)sizeof *prfctx);
+ goto cleanprf;
+ }
+ prf->prfctx = prfctx;
+
+ prfctx->ctx = malloc(hash->ctxsize);
+ if (!prfctx->ctx) {
+ log_error("prf_alloc: malloc (%d) failed",
+ hash->ctxsize);
+ goto cleanprfctx;
+ }
+ prfctx->ctx2 = malloc(hash->ctxsize);
+ if (!prfctx->ctx2) {
+ log_error("prf_alloc: malloc (%d) failed",
+ hash->ctxsize);
+ free(prfctx->ctx);
+ goto cleanprfctx;
+ }
+ prf->type = PRF_HMAC;
+ prf->blocksize = hash->hashsize;
+ prfctx->hash = hash;
+
+ /* Use the correct function pointers. */
+ prf->Init = (void(*)(void *))prf_hash_init;
+ prf->Update = (void(*)(void *, unsigned char *,
+ unsigned int))prf_hash_update;
+ prf->Final = (void(*)(unsigned char *, void *))prf_hash_final;
+
+ /* Init HMAC contexts. */
+ hash->HMACInit(hash, shared, sharedsize);
+
+ /* Save contexts. */
+ memcpy(prfctx->ctx, hash->ctx, hash->ctxsize);
+ memcpy(prfctx->ctx2, hash->ctx2, hash->ctxsize);
+ }
+ return prf;
+
+cleanprfctx:
+ free(prf->prfctx);
+cleanprf:
+ free(prf);
+ return 0;
+}
+
+/* Deallocate the PRF pointed to by PRF. */
+void
+prf_free(struct prf *prf)
+{
+ struct prf_hash_ctx *prfctx = prf->prfctx;
+
+ if (prf->type == PRF_HMAC) {
+ free(prfctx->ctx2);
+ free(prfctx->ctx);
+ }
+ free(prf->prfctx);
+ free(prf);
+}
diff --git a/keyexchange/isakmpd-20041012/prf.h b/keyexchange/isakmpd-20041012/prf.h
new file mode 100644
index 0000000..08a6fb3
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/prf.h
@@ -0,0 +1,58 @@
+/* $OpenBSD: prf.h,v 1.10 2004/04/15 18:39:26 deraadt Exp $ */
+/* $EOM: prf.h,v 1.1 1998/07/11 20:06:22 provos Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _PRF_H_
+#define _PRF_H_
+
+/* Enumeration of possible PRF - Pseudo-Random Functions. */
+enum prfs {
+ PRF_HMAC = 0 /* No PRFs in drafts, this is the default */
+};
+
+struct prf {
+ enum prfs type; /* Type of PRF */
+ void *prfctx; /* Context for PRF */
+ u_int8_t blocksize; /* The blocksize of PRF */
+ void (*Init) (void *);
+ void (*Update) (void *, unsigned char *, unsigned int);
+ void (*Final) (unsigned char *, void *);
+};
+
+struct prf_hash_ctx {
+ struct hash *hash; /* Hash type to use */
+ void *ctx, *ctx2; /* Contexts we need for later */
+};
+
+struct prf *prf_alloc(enum prfs, int, unsigned char *, unsigned int);
+void prf_free(struct prf *);
+
+#endif /* _PRF_H_ */
diff --git a/keyexchange/isakmpd-20041012/regress/Makefile b/keyexchange/isakmpd-20041012/regress/Makefile
new file mode 100644
index 0000000..bcbf7e5
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/Makefile
@@ -0,0 +1,34 @@
+# $OpenBSD: Makefile,v 1.9 2003/06/03 14:39:50 ho Exp $
+# $EOM: Makefile,v 1.8 1999/07/17 20:44:13 niklas Exp $
+
+#
+# Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+SUBDIR= b2n crypto dh ec2n exchange group hmac prf rsakeygen util x509
+
+.include <bsd.subdir.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/b2n/.cvsignore b/keyexchange/isakmpd-20041012/regress/b2n/.cvsignore
new file mode 100644
index 0000000..ed605b2
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/b2n/.cvsignore
@@ -0,0 +1,2 @@
+b2ntest
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/b2n/Makefile b/keyexchange/isakmpd-20041012/regress/b2n/Makefile
new file mode 100644
index 0000000..57ffb1f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/b2n/Makefile
@@ -0,0 +1,16 @@
+# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $
+# $EOM: Makefile,v 1.12 2000/10/13 13:04:17 ho Exp $
+
+# Test some math
+
+PROG= b2ntest
+SRCS= b2ntest.c conf.c log.c math_2n.c sysdep.c util.c
+NOMAN=
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/b2n/b2ntest.c b/keyexchange/isakmpd-20041012/regress/b2n/b2ntest.c
new file mode 100644
index 0000000..97284db
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/b2n/b2ntest.c
@@ -0,0 +1,368 @@
+/* $OpenBSD: b2ntest.c,v 1.8 2003/06/03 14:39:50 ho Exp $ */
+/* $EOM: b2ntest.c,v 1.4 1998/07/16 19:31:55 provos Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * B2N is a module for doing arithmetic on the Field GF(2**n) which is
+ * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an
+ * irreduciable polynomial over GF(2)[x] with grade n.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "math_2n.h"
+
+#define BUFSIZE 200
+
+#define CMP_FAIL(n,x) b2n_snprint (buf, BUFSIZE, n); if (strcmp (buf, (x))) \
+ printf ("FAILED: %s != %s ", buf, x); else printf ("OKAY ");
+
+int
+main (void)
+{
+ int i;
+ b2n_t n, m, d, r;
+ char buf[BUFSIZE];
+
+ b2n_init (n);
+ b2n_init (m);
+ b2n_init (d);
+ b2n_init (r);
+
+ printf ("Arithimetic Tests for GF(2)[x]:\n");
+ printf ("Testing: b2n_set*: ");
+ b2n_set_ui (n, 0xffc0);
+ CMP_FAIL (n, "0xffc0");
+
+ b2n_set_str (m, "0x180c0");
+ CMP_FAIL (m, "0x0180c0");
+ b2n_set_str (m, "0x808b8080c0");
+ CMP_FAIL (m, "0x808b8080c0");
+
+ printf ("\nTesting: b2n_add: ");
+ b2n_add (d, n, m);
+ CMP_FAIL (d, "0x808b807f00");
+ b2n_add (n, n, m);
+ CMP_FAIL (n, "0x808b807f00");
+ b2n_add (n, n, n);
+ CMP_FAIL (n, "0x00");
+ b2n_set_str (n, "0x9090900000000000000000");
+ b2n_set_ui (m, 0);
+ b2n_add (n, n, m);
+ CMP_FAIL (n, "0x9090900000000000000000");
+
+ printf ("\nTesting: b2n_lshift: ");
+ b2n_set_str (m, "0x808b8080c0");
+ b2n_lshift (n, m, 3);
+ CMP_FAIL (n, "0x04045c040600");
+ b2n_lshift (n, m, 11);
+ CMP_FAIL (n, "0x04045c04060000");
+ b2n_set (n, m);
+ for (i = 0; i < 11; i++)
+ b2n_lshift (n, n, 1);
+ CMP_FAIL (n, "0x04045c04060000");
+ b2n_lshift (d, m, 12);
+ CMP_FAIL (d, "0x0808b8080c0000");
+ b2n_set_str (m, "0xdeadbeef");
+ b2n_lshift (d, m, 103);
+ CMP_FAIL (d, "0x6f56df7780000000000000000000000000");
+
+ printf ("\nTesting: b2n_rshift: ");
+ b2n_rshift (m, n, 3);
+ CMP_FAIL (m, "0x808b8080c000");
+ b2n_rshift (m, m, 11);
+ CMP_FAIL (m, "0x1011701018");
+ b2n_set_str (m, "0x12381998713258186712365");
+ b2n_rshift (m, m, 23);
+ CMP_FAIL (m, "0x024703330e264b030c");
+ b2n_set_str (m, "0x12381998713258186712365");
+ for (i=0; i<23; i++)
+ b2n_rshift (m, m, 1);
+ CMP_FAIL (m, "0x024703330e264b030c");
+
+ printf ("\nTesting: b2n_mul: 0x9 o 0x5: ");
+ b2n_set_ui (n, 9);
+ b2n_set_ui (m, 5);
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x2d");
+ b2n_mul (n, n, m);
+ CMP_FAIL (d, "0x2d");
+
+ printf ("\nTesting: b2n_mul: 0x9 o 0x0: ");
+ b2n_set_ui (n, 9);
+ b2n_set_ui (m, 0);
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x00");
+ b2n_set_ui (n, 0);
+ b2n_set_ui (m, 9);
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x00");
+
+ printf ("\nTesting: b2n_mul: 0x9 o 0x1: ");
+ b2n_set_ui (n, 9);
+ b2n_set_ui (m, 1);
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x09");
+
+ printf ("\nTesting: b2n_mul: 0x12329 o 0x1235: ");
+ b2n_set_str (n, "0x12329");
+ b2n_set_str (m, "0x1235");
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x10473a3d");
+ b2n_mul (n, n, m);
+ CMP_FAIL (d, "0x10473a3d");
+
+ printf ("\nTesting: b2n_square: 0x1235 o 0x1235: ");
+ b2n_set_str (m, "0x1235");
+ b2n_square (n, m);
+ CMP_FAIL (n, "0x01040511");
+
+ printf ("\nTesting: b2n_square: 0x80c1235 o 0x80c1235: ");
+ b2n_set_str (m, "0x80c1235");
+ b2n_square (n, m);
+ CMP_FAIL (n, "0x40005001040511");
+
+ b2n_set_str (m, "0x12329");
+ printf ("\nTesting: sigbit: 0x12329: %d, %s",
+ b2n_sigbit(m), b2n_sigbit(m) == 17 ? "OKAY" : "FAILED");
+ b2n_set_ui (m, 0);
+ printf ("\nTesting: sigbit: 0x0: %d, %s",
+ b2n_sigbit(m), b2n_sigbit(m) == 0 ? "OKAY" : "FAILED");
+ b2n_set_str (m, "0x7f3290000");
+ printf ("\nTesting: sigbit: 0x7f3290000: %d, %s",
+ b2n_sigbit(m), b2n_sigbit(m) == 35 ? "OKAY" : "FAILED");
+
+ printf ("\nTesting: b2n_cmp: ");
+ b2n_set_str (m, "0x2234");
+ b2n_set_str (n, "0x1234");
+ printf ("%d <-> %d, ", b2n_sigbit (m), b2n_sigbit(n));
+ printf ("%d, %d ,%d: ", b2n_cmp (m,m), b2n_cmp (m,n), b2n_cmp (n,m));
+ if (b2n_cmp (m,m) || b2n_cmp (m,n) != 1 || b2n_cmp (n,m) != -1)
+ printf ("FAILED");
+ else
+ printf ("OKAY");
+ printf ("\nTesting: b2n_cmp_null: ");
+ b2n_set_str (m, "0x2234");
+ b2n_set_ui (n, 0);
+ printf ("%d, %d: ", b2n_cmp_null (m), b2n_cmp_null (n));
+ if (b2n_cmp_null (m) != 1 || b2n_cmp_null (n))
+ printf ("FAILED");
+ else
+ printf ("OKAY");
+
+ printf ("\nTesting: b2n_div: 0x2d / 0x5: ");
+ b2n_set_str (n, "0x2d");
+ b2n_set_ui (m, 5);
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x09");
+ CMP_FAIL (m, "0x00");
+ printf ("\nTesting: b2n_div: 0x2d / 0x1: ");
+ b2n_set_str (n, "0x2d");
+ b2n_set_ui (m, 1);
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x2d");
+ CMP_FAIL (m, "0x00");
+
+ printf ("\nTesting: b2n_div: 0x10473a3d / 0x1235: ");
+ b2n_set_str (n, "0x10473a3d");
+ b2n_set_str (m, "0x1235");
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x012329");
+ CMP_FAIL (m, "0x00");
+
+ printf ("\nTesting: b2n_div: 0x10473a3d / 0x1536: ");
+ b2n_set_str (n, "0x10473a3d");
+ b2n_set_str (m, "0x1536");
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x014331");
+ CMP_FAIL (m, "0xab");
+ b2n_set_str (n, "0x10473a3d");
+ b2n_set_str (m, "0x1536");
+ b2n_div_q (d, n, m);
+ CMP_FAIL (d, "0x014331");
+ b2n_div_r (d, n, m);
+ CMP_FAIL (d, "0xab");
+
+ printf ("\nTesting: b2n_div: "
+ "0x0800000000000000000000004000000000000001 / 0xffab09909a00: ");
+ b2n_set_str (n, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0xffab09909a00");
+ b2n_div_q (d, n, m);
+ CMP_FAIL (d, "0x18083e83a98647cedae0b3e69a5e");
+ b2n_div_r (d, n, m);
+ CMP_FAIL (d, "0x5b8bf98cac01");
+ b2n_set (d, m);
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x18083e83a98647cedae0b3e69a5e");
+ CMP_FAIL (m, "0x5b8bf98cac01");
+
+ printf ("\nTesting: b2n_div: "
+ "0x0800000000000000000000004000000000000001 / 0x7b: ");
+ b2n_set_str (n, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0x7b");
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x32dea27065bd44e0cb7a89c000000000000000");
+ CMP_FAIL (m, "0x01");
+
+ printf ("\n\nArithimetic Tests for GF(2**m) ~= GF(2)[x]/p(x):\n");
+ printf ("Testing: b2n_gcd: ");
+ b2n_set_str (d, "0x771");
+ b2n_set_str (m, "0x26d");
+ b2n_gcd (n, m, d);
+ CMP_FAIL (n, "0x0b");
+ b2n_set_str (d, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0xffab09909a00");
+ b2n_gcd (n, m, d);
+ CMP_FAIL (n, "0x01");
+ b2n_set_str (d, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0x7b");
+ b2n_gcd (n, m, d);
+ CMP_FAIL (n, "0x01");
+
+ printf ("\nTesting: b2n_mul_inv: ");
+ b2n_set_str (d, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0xffab09909a00");
+ b2n_mul_inv (n, m, d);
+ CMP_FAIL (n, "0x074029149f69304174d28858ae5c60df208a22a8");
+ b2n_set_str (n, "0xffab09909a00");
+ b2n_mul_inv (n, n, d);
+ CMP_FAIL (n, "0x074029149f69304174d28858ae5c60df208a22a8");
+ b2n_mul (n, n, m);
+ b2n_mod (n, n, d);
+ CMP_FAIL (n, "0x01");
+ b2n_set_str (d, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0x7b");
+ b2n_mul_inv (n, m, d);
+ CMP_FAIL (n, "0x32dea27065bd44e0cb7a89c000000000000000");
+ b2n_mul (n, n, m);
+ b2n_mod (n, n, d);
+ CMP_FAIL (n, "0x01");
+
+ printf ("\nTesting: b2n_random: ");
+ b2n_random (m, 155);
+ b2n_snprint (buf, BUFSIZE, m);
+ printf ("%s, %d", buf, b2n_sigbit(m));
+
+ printf ("\nTesting: b2n_sqrt: ");
+ b2n_set_str (n, "0x0800000000000000000000004000000000000001");
+ b2n_set_ui (d, 2);
+ b2n_sqrt (m, d, n);
+ b2n_square (d, m);
+ b2n_add (d, d, m);
+ b2n_mod (d, d, n);
+ CMP_FAIL (d, "0x02");
+
+ /* x**3 + b */
+ b2n_set_ui (n, 0x7b);
+ b2n_square (d, n);
+ b2n_mul (d, d, n);
+ b2n_set_str (n, "0x07338f");
+ b2n_add (d, d, n);
+ b2n_set_str (n, "0x0800000000000000000000004000000000000001");
+ b2n_mod (d, d, n);
+ /* \alpha = x**3 + b - end */
+
+ /* \beta = x**(-2)*\alpha */
+ b2n_set_ui (m, 0x7b);
+ b2n_mul_inv (m, m, n);
+ b2n_square (m, m);
+ b2n_mod (m, m, n);
+ b2n_mul (d, d, m);
+ b2n_mod (d, d, n);
+ b2n_set (r, d);
+ /* \beta = x**(-2)*\alpha - end */
+
+ b2n_sqrt (m, d, n);
+ CMP_FAIL (m, "0x0690aec7cd215d8f9a42bb1f0000000000000004");
+ b2n_square (d, m);
+ b2n_mod (d, d, n);
+ b2n_add (d, d, m);
+ b2n_mod (d, d, n);
+ printf ("Squaring Check: ");
+ CMP_FAIL (d, "0x03d5af92c8311d9e8f56be4b3e690aec7cd215cc");
+
+ printf ("\nTesting: b2n_trace: ");
+ b2n_set_ui (m, 2);
+ b2n_trace (d, m, n);
+ CMP_FAIL (d, "0x00");
+ b2n_set_ui (m, 0x11223);
+ b2n_trace (d, m, n);
+ CMP_FAIL (d, "0x01");
+
+ printf ("\nTesting: b2n_exp_mod: ");
+ b2n_set_ui (m, 0x7b);
+ b2n_exp_mod (d, m, 5, n);
+ CMP_FAIL (d, "0x7cccb7cb");
+ b2n_set_str (m, "0x123456789abcdef");
+ b2n_exp_mod (d, m, 13, n);
+ CMP_FAIL (d, "0x043f0a8550cb69b3c50d0340d1c6d5c97ecd60d4");
+
+ printf ("\nTesting: b2n_3mul: ");
+ b2n_set_ui (m, 0x7b);
+ b2n_3mul (m, m);
+ CMP_FAIL (m, "0x0171");
+
+ b2n_set_ui (m, 0x7fffffff);
+ b2n_3mul (m, m);
+ CMP_FAIL (m, "0x017ffffffd");
+
+ printf ("\nTesting: b2n_nadd: ");
+ b2n_set_str (m, "0x7fffffff");
+ b2n_set_str (n, "0x10203045");
+ b2n_nadd (d, n, m);
+ CMP_FAIL (d, "0x90203044");
+
+ b2n_set_str (m, "0x9a4a54d8b8dfa566112849991214329a233d");
+ b2n_set_str (n, "0x70ee40dd60c8657e58eda9a17ad9176e28b4b457e5a34a0948e335");
+ b2n_nadd (d, n, m);
+ CMP_FAIL (d, "0x70ee40dd60c8657e5987f3f65391f7138ec5dca17eb55e3be30672");
+
+ printf ("\nTesting: b2n_nsub: ");
+ b2n_set_str (n, "0x90203044");
+ b2n_set_str (m, "0x10203045");
+ b2n_nsub (d, n, m);
+ CMP_FAIL (d, "0x7fffffff");
+
+ b2n_set_str (n, "0x70ee40dd60c8657e5987f3f65391f7138ec5dca17eb55e3be30672");
+ b2n_set_str (m, "0x70ee40dd60c8657e58eda9a17ad9176e28b4b457e5a34a0948e335");
+ b2n_nsub (d, n, m);
+ CMP_FAIL (d, "0x9a4a54d8b8dfa566112849991214329a233d");
+
+ b2n_clear (n);
+ b2n_clear (m);
+ b2n_clear (d);
+ b2n_clear (r);
+
+ printf ("\n");
+ return 1;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/check.sh b/keyexchange/isakmpd-20041012/regress/check.sh
new file mode 100644
index 0000000..ea726c5
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/check.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+# $OpenBSD: check.sh,v 1.4 2003/06/03 14:39:50 ho Exp $
+# $EOM: check.sh,v 1.4 1998/07/17 21:33:13 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson.
+#
+
+PROGNAME=$0
+NC=/usr/bin/nc
+HOST=localhost
+ISAKMP_PORT=500
+
+set -- `getopt p: $*`
+if [ $? != 0 ]; then
+ echo 'usage: $PROGNAME [-p port] host' >&2
+ exit 2
+fi
+for i; do
+ case "$i" in
+ -p)
+ ISAKMP_PORT=$2; shift; shift;;
+ --)
+ shift; break;;
+ esac
+done
+
+if [ $# -gt 0 ]; then
+ HOST=$1
+fi
+
+send () {
+ ${NC} -u -w 1 ${HOST} ${ISAKMP_PORT}
+}
+
+# Short message
+printf "SHORT!" |send
+
+# (Most probably) invalid cookie
+printf "INVALID COOKIES!\0\x10\0\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid next payload type
+printf "01234567\0\0\0\0\0\0\0\0!\x10\0\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid major version
+printf "01234567\0\0\0\0\0\0\0\0\0\x20\0\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid minor version
+printf "01234567\0\0\0\0\0\0\0\0\0\x11\0\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid exchange type
+printf "01234567\0\0\0\0\0\0\0\0\0\x10!\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid flags
+printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\x80\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid message ID
+printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0BAD!\0\0\0\x1c" |send
+
+# Short length
+printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0\0\0\0\0\0\0\0\x1b" |send
+
+# Long length
+printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0\0\0\0\0\0\0\0\x1d" |send
diff --git a/keyexchange/isakmpd-20041012/regress/crypto/.cvsignore b/keyexchange/isakmpd-20041012/regress/crypto/.cvsignore
new file mode 100644
index 0000000..7b3c6ec
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/crypto/.cvsignore
@@ -0,0 +1,2 @@
+cryptotest
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/crypto/Makefile b/keyexchange/isakmpd-20041012/regress/crypto/Makefile
new file mode 100644
index 0000000..b2a0ef9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/crypto/Makefile
@@ -0,0 +1,20 @@
+# $OpenBSD: Makefile,v 1.11 2004/02/25 16:01:29 hshoexer Exp $
+# $EOM: Makefile,v 1.7 2000/03/28 21:22:06 ho Exp $
+
+# Test Crypto:
+
+PROG= cryptotest
+SRCS= crypto.c cryptotest.c conf.c log.c sysdep.c util.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \
+ -DUSE_TRIPLEDES -DUSE_CAST -DUSE_BLOWFISH -DUSE_DES \
+ -DUSE_AES
+LDADD+= -lcrypto -ldes
+DPADD+= ${LIBCRYPTO} ${LIBDES}
+NOMAN=
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/crypto/cryptotest.c b/keyexchange/isakmpd-20041012/regress/crypto/cryptotest.c
new file mode 100644
index 0000000..d860ddd
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/crypto/cryptotest.c
@@ -0,0 +1,178 @@
+/* $OpenBSD: cryptotest.c,v 1.13 2004/04/07 22:45:50 ho Exp $ */
+/* $EOM: cryptotest.c,v 1.5 1998/10/07 16:40:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "crypto.h"
+
+void test_crypto (enum transform);
+
+#define SET_KEY(x,y) {size_t i; for (i=0; i < (y); i++) (x)[i] = i;}
+
+int
+verify_buf (u_int8_t *buf, u_int16_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (buf[i] != i)
+ return 0;
+
+ return 1;
+}
+
+#define nibble2bin(y) (tolower((y)) < 'a' ? (y) - '0': tolower((y)) - 'a' + 10)
+#define hexchar2bin(x) ((nibble2bin((x)[0]) << 4) + nibble2bin((x)[1]))
+#define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x)))
+
+static void asc2bin (u_int8_t *bin, u_int8_t *asc, u_int16_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i += 2, asc += 2)
+ {
+ *bin++ = hexchar2bin(asc);
+ }
+}
+
+void
+special_test_blf (void)
+{
+ u_int8_t *akey = "0123456789ABCDEFF0E1D2C3B4A59687";
+ u_int8_t *aiv = "FEDCBA9876543210";
+ u_int8_t data[] = "7654321 Now is the time for \0\0\0"; /* len 29 */
+ u_int8_t *acipher
+ = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CCE7";
+ u_int8_t key[16], cipher[32], iv[8];
+ struct crypto_xf *xf;
+ struct keystate *ks;
+ enum cryptoerr err;
+ int i;
+
+ asc2bin (key, akey, strlen (akey));
+ asc2bin (iv, aiv, strlen (aiv));
+ asc2bin (cipher, acipher, 64);
+
+ xf = crypto_get (BLOWFISH_CBC);
+ printf ("Special Test-Case %s: ", xf->name);
+
+ ks = crypto_init (xf, key, 16, &err);
+ if (!ks)
+ {
+ printf ("FAILED (init %d)", err);
+ goto fail;
+ }
+
+ crypto_init_iv (ks, iv, xf->blocksize);
+ crypto_encrypt (ks, data, 32);
+
+ for (i = 0; i < 32; i++)
+ if (data[i] != cipher[i])
+ break;
+ if (i < 32)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ free (ks);
+
+fail:
+ printf ("\n");
+ return;
+}
+
+int
+main (void)
+{
+ test_crypto (DES_CBC);
+
+ test_crypto (TRIPLEDES_CBC);
+
+ test_crypto (BLOWFISH_CBC);
+
+ test_crypto (CAST_CBC);
+
+ test_crypto (AES_CBC);
+
+ special_test_blf ();
+
+ return 1;
+}
+
+void
+dump_buf (u_int8_t *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ printf ("%02x ", buf[i]);
+ printf ("\n");
+}
+
+void
+test_crypto (enum transform which)
+{
+ u_int8_t buf[256];
+ struct crypto_xf *xf;
+ struct keystate *ks;
+ enum cryptoerr err;
+
+ xf = crypto_get (which);
+ printf ("Testing %s: ", xf->name);
+
+ SET_KEY (buf, xf->keymax);
+ ks = crypto_init (xf, buf, xf->keymax, &err);
+ if (!ks)
+ {
+ printf ("FAILED (init %d)", err);
+ goto fail;
+ }
+ SET_KEY (buf, sizeof (buf));
+ crypto_init_iv (ks, buf, xf->blocksize);
+ crypto_encrypt (ks, buf, sizeof (buf));
+ dump_buf (buf, sizeof buf);
+ crypto_decrypt (ks, buf, sizeof (buf));
+ if (!verify_buf (buf, sizeof (buf)))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ free (ks);
+
+ fail:
+ printf ("\n");
+ return;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/dh/.cvsignore b/keyexchange/isakmpd-20041012/regress/dh/.cvsignore
new file mode 100644
index 0000000..d47de54
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/dh/.cvsignore
@@ -0,0 +1,2 @@
+dhtest
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/dh/Makefile b/keyexchange/isakmpd-20041012/regress/dh/Makefile
new file mode 100644
index 0000000..e7f8d79
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/dh/Makefile
@@ -0,0 +1,29 @@
+# $OpenBSD: Makefile,v 1.8 2004/02/25 16:01:29 hshoexer Exp $
+# $EOM: Makefile,v 1.10 2000/04/07 20:19:43 niklas Exp $
+
+# Test DH:
+
+PROG= dhtest
+SRCS= math_2n.c math_ec2n.c math_group.c dh.c dhtest.c log.c util.c \
+ sysdep.c gmp_util.c conf.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//'
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \
+ -DUSE_EC
+NOMAN=
+LDADD+= -lcrypto
+DPADD+= ${LIBCRYPTO}
+DEBUG= -g
+
+.if ${FEATURES:Mgmp} == "gmp"
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+.else
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
+.endif
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/dh/dhtest.c b/keyexchange/isakmpd-20041012/regress/dh/dhtest.c
new file mode 100644
index 0000000..ef23caf
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/dh/dhtest.c
@@ -0,0 +1,102 @@
+/* $OpenBSD: dhtest.c,v 1.5 2003/06/03 14:39:50 ho Exp $ */
+/* $EOM: dhtest.c,v 1.1 1998/07/18 21:14:20 provos Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * This module does a Diffie-Hellman Exchange
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "math_group.h"
+#include "dh.h"
+
+#define DUMP_X(_x_) point = (_x_); b2n_print (point->x);
+
+int
+main (void)
+{
+ int len;
+ char buf[100], buf2[100];
+ char sec[100], sec2[100];
+ struct group *group, *group2;
+
+ group_init ();
+ group = group_get (4);
+ group2 = group_get (4);
+
+ printf ("Testing DH (elliptic curve): \n");
+
+ printf ("dh_getlen\n");
+ len = dh_getlen (group);
+ printf ("dh_create_exchange\n");
+ dh_create_exchange (group, buf);
+ dh_create_exchange (group2, buf2);
+
+ printf ("dh_create_shared\n");
+ dh_create_shared (group, sec, buf2);
+ dh_create_shared (group2, sec2, buf);
+
+ printf ("Result: ");
+ if (memcmp (sec, sec2, len))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ group_free (group);
+ group_free (group2);
+
+ printf ("\nTesting DH (MODP): \n");
+
+ group = group_get (1);
+ group2 = group_get (1);
+
+ printf ("dh_getlen\n");
+ len = dh_getlen (group);
+ printf ("dh_create_exchange\n");
+ dh_create_exchange (group, buf);
+ dh_create_exchange (group2, buf2);
+
+ printf ("dh_create_shared\n");
+ dh_create_shared (group, sec, buf2);
+ dh_create_shared (group2, sec2, buf);
+
+ printf ("Result: ");
+ if (memcmp (sec, sec2, len))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+
+ printf ("\n");
+ return 1;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/ec2n/.cvsignore b/keyexchange/isakmpd-20041012/regress/ec2n/.cvsignore
new file mode 100644
index 0000000..6f2d7c6
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/ec2n/.cvsignore
@@ -0,0 +1,2 @@
+ec2ntest
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/ec2n/Makefile b/keyexchange/isakmpd-20041012/regress/ec2n/Makefile
new file mode 100644
index 0000000..827ecbe
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/ec2n/Makefile
@@ -0,0 +1,16 @@
+# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $
+# $EOM: Makefile,v 1.9 2000/10/13 13:04:17 ho Exp $
+
+# Test EC2N:
+
+PROG= ec2ntest
+SRCS= math_2n.c math_ec2n.c ec2ntest.c log.c sysdep.c util.c conf.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+NOMAN=
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/ec2n/ec2ntest.c b/keyexchange/isakmpd-20041012/regress/ec2n/ec2ntest.c
new file mode 100644
index 0000000..0535e8c
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/ec2n/ec2ntest.c
@@ -0,0 +1,144 @@
+/* $OpenBSD: ec2ntest.c,v 1.5 2003/06/04 07:31:17 ho Exp $ */
+/* $EOM: ec2ntest.c,v 1.3 1998/07/16 09:21:59 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * B2N is a module for doing arithmetic on the Field GF(2**n) which is
+ * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an
+ * irreduciable polynomial over GF(2)[x] with grade n.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "math_2n.h"
+#include "math_ec2n.h"
+
+#define BUFSIZE 200
+
+#define CMP_FAIL(n,x) b2n_snprint (buf, BUFSIZE, n); if (strcmp (buf, (x))) \
+ printf ("FAILED: %s != %s ", buf, x); else printf ("OKAY ");
+
+int
+main (void)
+{
+ b2n_t k;
+ ec2np_t p, q, r;
+ ec2ng_t g;
+ char buf[BUFSIZE];
+
+ b2n_init (k);
+ ec2np_init (p);
+ ec2np_init (q);
+ ec2np_init (r);
+ ec2ng_init (g);
+
+ printf ("Testing: ec2ng_set* :");
+ /* Init Group */
+ ec2ng_set_p_str (g, "0x0800000000000000000000004000000000000001");
+ CMP_FAIL (g->p, "0x0800000000000000000000004000000000000001");
+ ec2ng_set_a_ui (g, 0);
+ CMP_FAIL (g->a, "0x00");
+ ec2ng_set_b_str (g, "0x07338f");
+ CMP_FAIL (g->b, "0x07338f");
+
+ printf ("\nTesting: ec2np_find_y: ");
+ /* Init Point */
+ ec2np_set_x_ui (p, 0x7b);
+ ec2np_find_y (p, g);
+
+ CMP_FAIL (p->y, "0x01c8");
+
+ printf ("\nTesting: ec2np_ison: ");
+ if (ec2np_ison (p, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+
+ ec2np_set_x_ui (q, 0x4);
+ ec2np_find_y (q, g);
+ if (ec2np_ison (q, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+
+ printf ("\nTesting: ec2np_add: ");
+ ec2np_set (r, p);
+ b2n_add (r->y, r->y, r->x);
+ ec2np_add (r, r, p, g);
+ if (!r->inf)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ ec2np_add (q, p, q, g);
+ CMP_FAIL (q->x, "0x06f32d7cc82cec8612a87a86e026350fb7595469");
+ CMP_FAIL (q->y, "0x4ab92e21e51358ca8deab3fbbc9f7d8a7d1575");
+ if (ec2np_ison (q, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+
+ ec2np_add (p, q, q, g);
+ CMP_FAIL (p->x, "0x0390001461385559a22ac9b6181c1e1889b38451");
+ CMP_FAIL (p->y, "0x0188e61f38d747d7813c6a8b33d14dfb7418b04c");
+ if (ec2np_ison (p, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+
+ printf ("\nTesting: ec2np_mul: ");
+ b2n_set_ui (k, 57);
+ ec2np_set (q, p);
+ ec2np_mul (q, q, k, g);
+ if (ec2np_ison (q, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+ CMP_FAIL (q->x, "0x06bcf88caab88f99399350c46559da3b91afbf9d");
+
+ b2n_set_str (k, "0x0800000000000000000057db5698537193aef943");
+ ec2np_set (q, p);
+ ec2np_mul (q, q, k, g);
+ if (ec2np_ison (q, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+ CMP_FAIL (q->x, "0x0390001461385559a22ac9b6181c1e1889b38451");
+
+ printf ("\n");
+ ec2np_clear (p);
+ ec2np_clear (q);
+ ec2np_clear (r);
+ ec2ng_clear (g);
+ b2n_clear (k);
+ return 1;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/.cvsignore b/keyexchange/isakmpd-20041012/regress/exchange/.cvsignore
new file mode 100644
index 0000000..b672fde
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/.cvsignore
@@ -0,0 +1 @@
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/Makefile b/keyexchange/isakmpd-20041012/regress/exchange/Makefile
new file mode 100644
index 0000000..ac22db8
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/Makefile
@@ -0,0 +1,58 @@
+# $OpenBSD: Makefile,v 1.7 2003/06/03 14:39:50 ho Exp $
+# $EOM: Makefile,v 1.8 2000/03/28 21:22:07 ho Exp $
+
+#
+# Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+RUN= ISAKMPD=${TOPOBJ}/isakmpd ${.CURDIR}/run.sh
+
+TESTS= def
+
+all:
+
+test: ${TESTS:S/^/test-/}
+
+.for TEST in ${TESTS}
+test-${TEST}:
+.ifdef ONLY_INIT
+ @echo Testing "${TEST}" test as initiator
+ @${RUN} ${RUNFLAGS} ${.CURDIR}/${TEST}
+.endif
+.ifdef ONLY_RESP
+ @echo Testing "${TEST}" test as responder
+ @${RUN} -r ${RUNFLAGS} ${.CURDIR}/${TEST}
+.endif
+.endfor
+
+.include <bsd.obj.mk>
+.include <bsd.subdir.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/README b/keyexchange/isakmpd-20041012/regress/exchange/README
new file mode 100644
index 0000000..cd1555b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/README
@@ -0,0 +1,78 @@
+$OpenBSD: README,v 1.1 1999/08/05 22:41:39 niklas Exp $
+$EOM: README,v 1.1 1999/08/05 15:07:37 niklas Exp $
+
+XXX The old run.sh test-framework is obsoleted, it will go away anyday.
+
+We wanted to do a regression test environment which was flexible
+enough to be able to easily reproduce anomalies in isakmpd. It
+turns out this is not easy to do, as many problems are timing related.
+
+Currently ticks are milliseconds. An idea is to try to measure
+isakmpd's response time somehow, and use that time as some kind of
+basis for a tick.
+
+Our test environment should be able to parse scripts like this:
+
+#Tick Action Format Data
+0 send H* ffffffff
+0 recv H* 00000000
+1000 send H* deadbeef
+
+Ticks are not absolute but relative to the last event. the format is
+Perl's pack/unpack template formats. Data is in the given format with
+one exception, spaces are ignored, newlines are end-of-data unless
+preceeded by a backslash.
+
+Comments are lines with a numbersign as the first non-whitespace
+character. Empty lines are ignored, unless inside a multi-line data
+in which it will be part of the data buffer.
+
+Here is a real world example:
+
+# $RCSId$
+
+# Initiate a MM
+0 send H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \
+ 00000050 00000034 00000001 00000001 00000028 01010001 \
+ 00000020 00010000 80010005 80020002 80030001 80040002 \
+ 800b0001 800c0258
+
+400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \
+ 00000050 00000034 00000001 00000001 00000028 01010001 \
+ 00000020 00010000 80010005 80020002 80030001 80040002 \
+ 800b0001 800c0258
+
+110 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \
+ 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \
+ f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \
+ 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \
+ 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \
+ 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \
+ bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \
+ 88e68a10 4ab19a6a 7e75c771
+
+800 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \
+ 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \
+ 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \
+ 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \
+ 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \
+ a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \
+ 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \
+ a406fd47 b3d16554 cd6f0967
+
+140 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \
+ 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \
+ 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \
+ 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5
+
+900 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \
+ 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \
+ b039fa72 d595e69f 03669dbd 350781e2 56c36dce
+
+run with:
+
+perl run.pl filename
+
+You need to have an isakmpd listening on the address which is given in
+run.pl. Of course you need to run it in deterministic mode (-r).
+There will be a better explanation soon.
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/def-i.1 b/keyexchange/isakmpd-20041012/regress/exchange/def-i.1
new file mode 100644
index 0000000..1712249
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/def-i.1
Binary files differ
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/def-r.1 b/keyexchange/isakmpd-20041012/regress/exchange/def-r.1
new file mode 100644
index 0000000..56f5e62
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/def-r.1
Binary files differ
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/mm-1-setup.sh b/keyexchange/isakmpd-20041012/regress/exchange/mm-1-setup.sh
new file mode 100644
index 0000000..0efd7c9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/mm-1-setup.sh
@@ -0,0 +1,12 @@
+# $OpenBSD: mm-1-setup.sh,v 1.2 2000/01/26 15:23:52 niklas Exp $
+# $EOM: mm-1-setup.sh,v 1.2 1999/10/05 12:54:27 niklas Exp $
+
+# XXX Need to start isakmpd here in a nice way.
+
+echo "C set [Phase 1]:127.0.0.1=localhost 1">/tmp/fifo
+echo "C set [localhost]:phase=1 1">/tmp/fifo
+echo "C set [localhost]:transport=udp 1">/tmp/fifo
+echo "C set [localhost]:address=127.0.0.1 1">/tmp/fifo
+echo "C set [localhost]:port=1501 1">/tmp/fifo
+echo "C set [localhost]:configuration=default-main-mode 1">/tmp/fifo
+echo "C set [localhost]:authentication=mekmitasdigoat 1">/tmp/fifo
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/mm-i-1.t b/keyexchange/isakmpd-20041012/regress/exchange/mm-i-1.t
new file mode 100644
index 0000000..9f9b1be
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/mm-i-1.t
@@ -0,0 +1,43 @@
+# $OpenBSD: mm-i-1.t,v 1.1 1999/08/05 22:41:39 niklas Exp $
+# $EOM: mm-i-1.t,v 1.1 1999/08/05 15:07:38 niklas Exp $
+
+# The seed to isakmpd was 19990805
+
+# Initiate a MM
+0 send H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \
+ 00000050 00000034 00000001 00000001 00000028 01010001 \
+ 00000020 00010000 80010005 80020002 80030001 80040002 \
+ 800b0001 800c0258
+
+400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \
+ 00000050 00000034 00000001 00000001 00000028 01010001 \
+ 00000020 00010000 80010005 80020002 80030001 80040002 \
+ 800b0001 800c0258
+
+110 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \
+ 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \
+ f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \
+ 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \
+ 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \
+ 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \
+ bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \
+ 88e68a10 4ab19a6a 7e75c771
+
+800 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \
+ 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \
+ 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \
+ 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \
+ 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \
+ a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \
+ 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \
+ a406fd47 b3d16554 cd6f0967
+
+140 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \
+ 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \
+ 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \
+ 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5
+
+900 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \
+ 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \
+ b039fa72 d595e69f 03669dbd 350781e2 56c36dce
+
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/mm-r-1.t b/keyexchange/isakmpd-20041012/regress/exchange/mm-r-1.t
new file mode 100644
index 0000000..0c48224
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/mm-r-1.t
@@ -0,0 +1,42 @@
+# $OpenBSD: mm-r-1.t,v 1.1 1999/08/05 22:41:39 niklas Exp $
+# $EOM: mm-r-1.t,v 1.1 1999/08/05 15:07:38 niklas Exp $
+
+# The seed to isakmpd was 19990805
+
+# Respond to this MM
+999999 recv H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \
+ 00000050 00000034 00000001 00000001 00000028 01010001 \
+ 00000020 00010000 80010005 80020002 80030001 80040002 \
+ 800b0001 800c0258
+
+40 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \
+ 00000050 00000034 00000001 00000001 00000028 01010001 \
+ 00000020 00010000 80010005 80020002 80030001 80040002 \
+ 800b0001 800c0258
+
+1100 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \
+ 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \
+ f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \
+ 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \
+ 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \
+ 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \
+ bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \
+ 88e68a10 4ab19a6a 7e75c771
+
+80 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \
+ 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \
+ 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \
+ 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \
+ 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \
+ a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \
+ 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \
+ a406fd47 b3d16554 cd6f0967
+
+1400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \
+ 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \
+ 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \
+ 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5
+
+90 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \
+ 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \
+ b039fa72 d595e69f 03669dbd 350781e2 56c36dce
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/run.pl b/keyexchange/isakmpd-20041012/regress/exchange/run.pl
new file mode 100644
index 0000000..d9fce2d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/run.pl
@@ -0,0 +1,105 @@
+#!/usr/bin/perl
+# $OpenBSD: run.pl,v 1.2 2004/01/26 14:56:03 niklas Exp $
+# $EOM: run.pl,v 1.2 1999/08/05 22:42:42 niklas Exp $
+
+#
+# Copyright (c) 2004 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+use strict;
+require 5.002;
+require 'sys/syscall.ph';
+use Socket;
+use Sys::Hostname;
+
+my ($rfd, $tickfac, $myaddr, $myport, $hisaddr, $hisport, $proto, $bindaddr,
+ $conaddr, $sec, $tick, $action, $template, $data, $next,
+ $nfd, $pkt, $verbose);
+
+$| = 1;
+
+$verbose = 1;
+$tickfac = 0.001;
+$myaddr = gethostbyname ('127.0.0.1');
+$myport = 1501;
+ $hisaddr = inet_aton ('127.0.0.1');
+$hisport = 1500;
+
+$proto = getprotobyname ('udp');
+$bindaddr = sockaddr_in ($myport, $myaddr);
+socket (SOCKET, PF_INET, SOCK_DGRAM, $proto) || die "socket: $!";
+bind (SOCKET, $bindaddr);
+vec ($rfd, fileno SOCKET, 1) = 1;
+
+$conaddr = sockaddr_in ($hisport, $hisaddr);
+
+sub getsec
+{
+ my ($tv) = pack ("ll", 0, 0);
+ my ($tz) = pack ("ii", 0, 0);
+ syscall (&SYS_gettimeofday, $tv, $tz) && return undef;
+ my ($sec, $usec) = unpack ("ll", $tv);
+ $sec % 86400 + $usec / 1000000;
+}
+
+$sec = &getsec;
+while (<>) {
+ next if /^\s*#/o || /^\s*$/o;
+ chop;
+ ($tick, $action, $template, $data) = split ' ', $_, 4;
+ while ($data =~ /\\$/o) {
+ chop $data;
+ $_ = <>;
+ next if /^\s*#/o;
+ chop;
+ $data .= $_;
+ }
+ $data =~ s/\s//go;
+ $data = pack $template, $data;
+ $next = $sec + $tick * $tickfac;
+ if ($action eq "send") {
+ # Wait for the moment to come.
+ print STDERR "waiting ", $next - $sec, " secs\n";
+ select undef, undef, undef, $next - $sec
+ while ($sec = &getsec) < $next;
+# print $data;
+ send SOCKET, $data, 0, $conaddr;
+ print STDERR "sent ", unpack ("H*", $data), "\n" if $verbose;
+ } elsif ($action eq "recv") {
+ $sec = &getsec;
+ printf (STDERR "waiting for data or the %.3f sec timeout\n",
+ $next - $sec);
+ $nfd = select $rfd, undef, undef, $next - $sec;
+ if ($nfd) {
+ printf STDERR "got back after %.3f secs\n", &getsec - $sec
+ if $verbose;
+# sysread (STDIN, $pkt, 65536) if $nfd;
+ sysread (SOCKET, $pkt, 65536) if $nfd;
+ print STDERR "read ", unpack ("H*", $pkt), "\n" if $verbose;
+ print STDERR "cmp ", unpack ("H*", $data), "\n" if $verbose;
+ } else {
+ print STDERR "timed out\n" if $verbose;
+ }
+ die "mismatch\n" if $pkt ne $data;
+ }
+}
diff --git a/keyexchange/isakmpd-20041012/regress/exchange/run.sh b/keyexchange/isakmpd-20041012/regress/exchange/run.sh
new file mode 100644
index 0000000..587c2c1
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/exchange/run.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+# $OpenBSD: run.sh,v 1.8 2004/01/09 10:03:04 hshoexer Exp $
+# $EOM: run.sh,v 1.6 1999/08/05 15:02:33 niklas Exp $
+
+#
+# Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# Defaults
+SRCPORT=1500
+DSTPORT=1501
+FIFO=test.fifo
+TIMEOUT=2
+
+NC=${NC:-/usr/bin/nc}
+ISAKMPD=${ISAKMPD:-/sbin/isakmpd}
+
+progname=`basename $0`
+indent=`echo -n $progname |sed 's/./ /g'`
+seed=980801
+initiator=yes
+retval=0
+verbose=no
+clean=yes
+
+usage ()
+{
+ echo "usage: $progname [-nrv] [-d dst-port] [-f fifo] [-s src-port]" >&2
+ echo " $indent [-t timeout] testsuite" >&2
+ exit 2
+}
+
+set -- `getopt d:f:nrs:t:v $*`
+if [ $? != 0 ]; then
+ usage
+fi
+for i; do
+ case "$i" in
+ -d)
+ DSTPORT=$2; shift; shift;;
+ -f)
+ FIFO=$2; shift; shift;;
+ -n)
+ clean=no; shift;;
+ -r)
+ initiator=no; shift;;
+ -s)
+ SRCPORT=$2; shift; shift;;
+ -t)
+ TIMEOUT=$2; shift; shift;;
+ -v)
+ verbose=yes; shift;;
+ --)
+ shift; break;;
+ esac
+done
+
+if [ $# -eq 1 ]; then
+ suite=$1
+else
+ usage
+fi
+
+[ ${verbose} = yes ] && set -x
+
+# Start isakmpd and wait for the fifo to get created
+rm -f ${FIFO}
+${ISAKMPD} -d -p${SRCPORT} -f${FIFO} -r${seed} &
+isakmpd_pid=$!
+trap 'kill $isakmpd_pid; rm -f${FIFO}; [ $clean = yes ] && rm -f packet' 1 2 15
+while [ ! -p ${FIFO} ]; do
+ sleep 1
+done
+
+# Start the exchange
+if [ $initiator = yes ]; then
+ ${NC} -nul -w${TIMEOUT} 127.0.0.1 ${DSTPORT} </dev/null >packet &
+# ${NC} -nu -w${TIMEOUT} -p${SRCPORT} 127.0.0.1 ${DSTPORT} </dev/null >packet
+ sleep 1
+ echo "c udp 127.0.0.1:${DSTPORT} 2 1" >${FIFO}
+ in_packets=`ls ${suite}-i.* 2>/dev/null`
+ out_packets=`ls ${suite}-r.* 2>/dev/null`
+else
+ in_packets=`ls ${suite}-r.* 2>/dev/null`
+ out_packets=`ls ${suite}-i.* 2>/dev/null`
+fi
+his_turn=$initiator
+while [ \( $his_turn = yes -a X"$in_packets" != X \) \
+ -o \( $his_turn = no -a X"$out_packets" != X \) ]; do
+ if [ $his_turn = no ]; then
+ set $out_packets
+ packet=$1
+ shift
+ out_packets=$*
+ cat $packet |${NC} -nu -w${TIMEOUT} -p${SRCPORT} 127.0.0.1 ${DSTPORT} \
+ >packet
+ my_turn=no
+ else
+ set $in_packets
+ packet=$1
+ shift
+ in_packets=$*
+ if ! cmp $packet packet 2>/dev/null; then
+ retval=1
+ break
+ fi
+ my_turn=yes
+ fi
+done
+kill $isakmpd_pid
+rm -f ${FIFO}
+[ $clean = yes ] && rm -f packet
+exit $retval
diff --git a/keyexchange/isakmpd-20041012/regress/group/.cvsignore b/keyexchange/isakmpd-20041012/regress/group/.cvsignore
new file mode 100644
index 0000000..2326f3a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/group/.cvsignore
@@ -0,0 +1,2 @@
+grouptest
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/group/Makefile b/keyexchange/isakmpd-20041012/regress/group/Makefile
new file mode 100644
index 0000000..9dc9982
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/group/Makefile
@@ -0,0 +1,29 @@
+# $OpenBSD: Makefile,v 1.8 2004/02/25 16:01:29 hshoexer Exp $
+# $EOM: Makefile,v 1.12 2000/04/07 20:19:43 niklas Exp $
+
+# Test Group:
+
+PROG= grouptest
+SRCS= math_2n.c math_ec2n.c math_group.c grouptest.c log.c util.c \
+ sysdep.c gmp_util.c conf.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//'
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \
+ -DUSE_EC
+NOMAN=
+LDADD+= -lcrypto
+DPADD+= ${LIBCRYPTO}
+DEBUG= -g
+
+.if ${FEATURES:Mgmp} == "gmp"
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+.else
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
+.endif
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/group/grouptest.c b/keyexchange/isakmpd-20041012/regress/group/grouptest.c
new file mode 100644
index 0000000..ba03283
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/group/grouptest.c
@@ -0,0 +1,121 @@
+/* $OpenBSD: grouptest.c,v 1.4 2003/06/03 14:39:51 ho Exp $ */
+/* $EOM: grouptest.c,v 1.2 1998/07/18 21:15:55 provos Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * This module exercises the operations supplied by the group abstraction.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "math_2n.h"
+#include "math_ec2n.h"
+#include "math_group.h"
+
+#define DUMP_X(_x_) point = (_x_); b2n_print (point->x);
+
+int
+main (void)
+{
+ int i;
+ char buf[100];
+ char buf2[100];
+ struct group *group, *group2;
+ ec2np_ptr point;
+
+ group_init ();
+ group = group_get (3);
+ group2 = group_get (3);
+
+ printf ("Testing: setraw, getraw: ");
+ for (i = 0; i < 20; i++)
+ buf[i] = i;
+
+ group->setraw (group, group->c, buf, 20);
+ if (group->getlen (group) != 20)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ group->getraw (group, group->c, buf2);
+ for (i = 0; i < 20; i++)
+ if (buf2[i] != i)
+ break;
+ if (i < 20)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ printf ("\nTesting: setrandom: ");
+ group->setrandom (group, group->c);
+ DUMP_X (group->c);
+ group2->setrandom (group2, group2->c);
+ DUMP_X (group2->c);
+
+ printf ("\nTesting: operation:\n");
+ group->operation (group, group->a, group->gen, group->c);
+ point = group->a;
+ printf ("\tX (%d): ", point->x->chunks); b2n_print (point->x);
+ printf ("\tY (%d): ", point->y->chunks); b2n_print (point->y);
+
+ group2->operation (group2, group2->a, group2->gen, group2->c);
+ point = group2->a;
+ printf ("\tX (%d): ", point->x->chunks); b2n_print (point->x);
+ printf ("\tY (%d): ", point->y->chunks); b2n_print (point->y);
+
+ printf ("Exchange Value 1: "); b2n_print (group->d);
+ printf ("Exchange Value 2: "); b2n_print (group2->d);
+
+ printf ("Testing: operation ...:\n");
+ group->getraw (group, group->a, buf);
+ group2->setraw (group2, group2->b, buf, 20);
+
+ group2->getraw (group2, group2->a, buf);
+ group->setraw (group, group->b, buf, 20);
+
+ group2->operation (group2, group2->a, group2->b, group2->c);
+ printf ("Exchange Value 21: "); DUMP_X (group2->a);
+
+ group->operation (group, group->a, group->b, group->c);
+ printf ("Exchange Value 12: "); DUMP_X (group->a);
+
+ group->getraw (group, group->a, buf);
+ group2->getraw (group2, group2->a, buf2);
+ printf ("Testing: operation ...: ");
+ if (memcmp(buf, buf2, 20))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ printf ("\n");
+ return 1;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/hmac/.cvsignore b/keyexchange/isakmpd-20041012/regress/hmac/.cvsignore
new file mode 100644
index 0000000..5fc5f86
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/hmac/.cvsignore
@@ -0,0 +1,2 @@
+hmactest
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/hmac/Makefile b/keyexchange/isakmpd-20041012/regress/hmac/Makefile
new file mode 100644
index 0000000..39bb2c7
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/hmac/Makefile
@@ -0,0 +1,16 @@
+# $OpenBSD: Makefile,v 1.4 1999/02/26 03:28:31 niklas Exp $
+# $EOM: Makefile,v 1.3 1999/02/25 15:14:24 niklas Exp $
+
+# Test HMAC:
+
+PROG= hmactest
+SRCS= hash.c hmactest.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+NOMAN=
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/hmac/hmactest.c b/keyexchange/isakmpd-20041012/regress/hmac/hmactest.c
new file mode 100644
index 0000000..3b86f06
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/hmac/hmactest.c
@@ -0,0 +1,93 @@
+/* $OpenBSD: hmactest.c,v 1.5 2003/06/04 07:31:17 ho Exp $ */
+/* $EOM: hmactest.c,v 1.3 1998/08/09 19:16:24 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hash.h"
+
+int test_hmac(char *, struct hash *, char *, int, char *, int, char *);
+
+#define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x)))
+
+int
+main (void)
+{
+ char key[100];
+
+ memset(key, 11, 20);
+ test_hmac ("HMAC-MD5 Test Case 1", hash_get (HASH_MD5),
+ key, 16, "Hi There", 8, "9294727a3638bb1c13f48ef8158bfc9d");
+ test_hmac ("HMAC-MD5 Test Case 2", hash_get (HASH_MD5),
+ "Jefe", 4,
+ "what do ya want for nothing?", 28,
+ "750c783e6ab0b503eaa86e310a5db738");
+ test_hmac ("HMAC-SHA1 Test Case 1", hash_get (HASH_SHA1),
+ key, 20, "Hi There", 8,
+ "b617318655057264e28bc0b6fb378c8ef146be00");
+ test_hmac ("HMAC-SHA1 Test Case 2", hash_get (HASH_SHA1),
+ "Jefe", 4, "what do ya want for nothing?", 28,
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
+
+ return 1;
+}
+
+int
+test_hmac(char *test, struct hash *hash, char *key, int klen,
+ char *data, int dlen, char *cmp)
+{
+ char output[2*HASH_MAX+1];
+ int i;
+
+ printf("Testing %s: ", test);
+
+ hash->HMACInit(hash, key, klen);
+ hash->Update(hash->ctx, data, dlen);
+ hash->HMACFinal(hash->digest, hash);
+
+ for (i=0; i<hash->hashsize; i++)
+ {
+ output[2*i] = nibble2c((hash->digest[i] >> 4) & 0xf);
+ output[2*i+1] = nibble2c(hash->digest[i] & 0xf);
+ }
+ output[2*i] = 0;
+
+ if (!strcmp(output, cmp))
+ {
+ printf("OKAY\n");
+ return 1;
+ }
+
+ printf("%s <-> %s\n", output, cmp);
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/prf/.cvsignore b/keyexchange/isakmpd-20041012/regress/prf/.cvsignore
new file mode 100644
index 0000000..023b310
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/prf/.cvsignore
@@ -0,0 +1,2 @@
+prftest
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/prf/Makefile b/keyexchange/isakmpd-20041012/regress/prf/Makefile
new file mode 100644
index 0000000..5d9b1fa
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/prf/Makefile
@@ -0,0 +1,16 @@
+# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $
+# $EOM: Makefile,v 1.6 2000/03/28 21:22:07 ho Exp $
+
+# Test PRF:
+
+PROG= prftest
+SRCS= prf.c hash.c log.c prftest.c conf.c sysdep.c util.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+NOMAN=
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/prf/prftest.c b/keyexchange/isakmpd-20041012/regress/prf/prftest.c
new file mode 100644
index 0000000..15d7578
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/prf/prftest.c
@@ -0,0 +1,116 @@
+/* $OpenBSD: prftest.c,v 1.7 2003/06/03 14:39:51 ho Exp $ */
+/* $EOM: prftest.c,v 1.2 1998/10/07 16:40:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "hash.h"
+#include "prf.h"
+
+int test_prf (char *, enum hashes, char *, int, char *, int, char *);
+
+#define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x)))
+
+/*
+ * Basically the same as the HMAC regress, but to keep with modularity
+ * prf seems to be useful. So here we just check the HMAC test cases,
+ * until there are more PRFs.
+ */
+
+int
+main (void)
+{
+ char key[100];
+
+ memset (key, 11, 20);
+ test_prf ("PRF MD5 Test Case 1", HASH_MD5,
+ key, 16, "Hi There", 8, "9294727a3638bb1c13f48ef8158bfc9d");
+ test_prf ("PRF MD5 Test Case 2", HASH_MD5,
+ "Jefe", 4,
+ "what do ya want for nothing?", 28,
+ "750c783e6ab0b503eaa86e310a5db738");
+ test_prf ("PRF SHA1 Test Case 1", HASH_SHA1,
+ key, 20, "Hi There", 8,
+ "b617318655057264e28bc0b6fb378c8ef146be00");
+ test_prf ("PRF SHA1 Test Case 2", HASH_SHA1,
+ "Jefe", 4, "what do ya want for nothing?", 28,
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
+ test_prf ("PRF SHA1 Test Case 3", HASH_SHA1,
+ "Bloody long key, this one, eben longer than the blocksize "
+ "of ordinary keyed HMAC functions", 90,
+ "what do ya want for nothing?", 28,
+ "52ca5fbcd7d4821bc6bf8b6e95e131109dff901b");
+
+ return 0;
+}
+
+int
+test_prf (char *test, enum hashes hash, char *key, int klen,
+ char *data, int dlen, char *cmp)
+{
+ char output[2*HASH_MAX+1];
+ char digest[HASH_MAX];
+ struct prf *prf;
+ int i;
+
+ printf ("Testing %s: ", test);
+
+ prf = prf_alloc (PRF_HMAC, hash, key, klen);
+ if (!prf)
+ {
+ printf("prf_alloc () failed\n");
+ return 0;
+ }
+
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, data, dlen);
+ prf->Final (digest, prf->prfctx);
+
+ prf_free (prf);
+
+ for (i = 0; i < prf->blocksize; i++)
+ {
+ output[2 * i] = nibble2c ((digest[i] >> 4) & 0xf);
+ output[2 * i + 1] = nibble2c (digest[i] & 0xf);
+ }
+ output[2 * i] = 0;
+
+ if (strcmp (output, cmp) == 0)
+ {
+ printf ("OKAY\n");
+ return 1;
+ }
+
+ printf ("%s <-> %s\n", output, cmp);
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/rsakeygen/.cvsignore b/keyexchange/isakmpd-20041012/regress/rsakeygen/.cvsignore
new file mode 100644
index 0000000..0ecb82e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/rsakeygen/.cvsignore
@@ -0,0 +1,4 @@
+isakmpd_key
+isakmpd_key.pub
+rsakeygen
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/rsakeygen/Makefile b/keyexchange/isakmpd-20041012/regress/rsakeygen/Makefile
new file mode 100644
index 0000000..578a7b5
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/rsakeygen/Makefile
@@ -0,0 +1,83 @@
+# $OpenBSD: Makefile,v 1.15 2004/02/25 16:01:29 hshoexer Exp $
+# $EOM: Makefile,v 1.10 2000/03/28 21:23:24 ho Exp $
+
+#
+# Copyright (c) 1999 Niels Provos. All rights reserved.
+# Copyright (c) 1999, 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# RSA Key Generation
+
+PROG= rsakeygen
+SRCS= libcrypto.c log.c rsakeygen.c sysdep.c util.c conf.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//'
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \
+ -DUSE_DEBUG
+NOMAN=
+DEBUG= -g
+
+.if ${FEATURES:Mgmp} == "gmp"
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+.else
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
+.endif
+
+.include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep"
+
+.ifdef HAVE_DLOPEN
+CFLAGS+= -DHAVE_DLOPEN
+SRCS+= dyn.c
+.endif
+
+.ifdef USE_LIBCRYPTO
+CFLAGS+= -DUSE_LIBCRYPTO
+LDADD+= -lcrypto
+DPADD+= ${LIBCRYPTO}
+.endif
+
+.if !defined (HAVE_DLOPEN) && !defined (USE_LIBCRYPTO)
+.BEGIN:
+ @echo RSA cannot be used in this environmet, skipping...
+
+PROG=
+.else
+# USE_X509 is required for libcrypto.h to include the correct headers,
+# but it is not set by ${OS}/Makefile.sysdep - setting it manually here
+# should be safe enough.
+CFLAGS+= -DUSE_X509
+.endif
+
+LDADD+= ${DESLIB}
+DPADD+= ${DESLIBDEP}
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/rsakeygen/rsakeygen.c b/keyexchange/isakmpd-20041012/regress/rsakeygen/rsakeygen.c
new file mode 100644
index 0000000..08548a0
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/rsakeygen/rsakeygen.c
@@ -0,0 +1,128 @@
+/* $OpenBSD: rsakeygen.c,v 1.19 2004/02/26 15:27:05 hshoexer Exp $ */
+/* $EOM: rsakeygen.c,v 1.10 2000/12/21 15:18:53 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libcrypto.h"
+#include "log.h"
+#include "math_mp.h"
+
+#define nibble2bin(y) (tolower (y) < 'a' ? (y) - '0' : tolower (y) - 'a' + 10)
+#define hexchar2bin(x) ((nibble2bin ((x)[0]) << 4) + nibble2bin ((x)[1]))
+#define nibble2c(x) ((x) >= 10 ? ('a' - 10 + (x)) : ('0' + (x)))
+
+#define TEST_STRING "!Dies ist ein Test"
+
+int
+main (void)
+{
+ u_int8_t enc[256], dec[256], *asn, *foo;
+ int len;
+ FILE *fd;
+ int erg = 0;
+ RSA *key;
+
+ libcrypto_init ();
+
+ log_debug_cmd (LOG_CRYPTO, 99);
+ memset (dec, '\0', sizeof dec);
+ strlcpy (dec, TEST_STRING, 256);
+
+ key = RSA_generate_key (1024, RSA_F4, NULL, NULL);
+ if (key == NULL)
+ {
+ printf("Failed to generate key\n");
+ return 0;
+ }
+
+ printf ("n: 0x");
+ BN_print_fp (stdout, key->n);
+ printf ("\ne: 0x");
+ BN_print_fp (stdout, key->e);
+ printf ("\n");
+
+ printf ("n: 0x");
+ BN_print_fp (stdout, key->n);
+ printf ("\ne: 0x");
+ BN_print_fp (stdout, key->e);
+ printf ("\nd: 0x");
+ BN_print_fp (stdout, key->d);
+ printf ("\np: 0x");
+ BN_print_fp (stdout, key->p);
+ printf ("\nq: 0x");
+ BN_print_fp (stdout, key->q);
+ printf ("\n");
+
+ printf ("Testing Signing/Verifying: ");
+ /* Sign with Private Key */
+ len = RSA_private_encrypt (strlen (dec) + 1, dec, enc, key,
+ RSA_PKCS1_PADDING);
+ if (len == -1)
+ printf ("SIGN FAILED ");
+ else
+ {
+ /* Decrypt/Verify with Public Key */
+ erg = RSA_public_decrypt (len, enc, dec, key, RSA_PKCS1_PADDING);
+
+ if (erg == -1 || strcmp (dec, TEST_STRING))
+ printf ("VERIFY FAILED");
+ else
+ printf ("OKAY");
+ }
+
+ printf ("\n");
+
+ len = i2d_RSAPublicKey (key, NULL);
+ foo = asn = malloc (len);
+ len = i2d_RSAPublicKey (key, &foo);
+ fd = fopen ("isakmpd_key.pub", "w");
+ fwrite (asn, len, 1, fd);
+ fclose (fd);
+ free (asn);
+
+ len = i2d_RSAPrivateKey (key, NULL);
+ foo = asn = malloc (len);
+ len = i2d_RSAPrivateKey (key, &foo);
+ fd = fopen ("isakmpd_key", "w");
+ fwrite (asn, len, 1, fd);
+ fclose (fd);
+ free (asn);
+
+ RSA_free (key);
+
+ return 1;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/util/Makefile b/keyexchange/isakmpd-20041012/regress/util/Makefile
new file mode 100644
index 0000000..88c0785
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/util/Makefile
@@ -0,0 +1,15 @@
+# $OpenBSD: Makefile,v 1.2 2004/02/25 16:01:29 hshoexer Exp $
+
+# Test some utility functions
+
+PROG= utiltest
+SRCS= log.c sysdep.c util.c utiltest.c conf.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+NOMAN=
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/util/utiltest.c b/keyexchange/isakmpd-20041012/regress/util/utiltest.c
new file mode 100644
index 0000000..89d8615
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/util/utiltest.c
@@ -0,0 +1,85 @@
+/* $OpenBSD: utiltest.c,v 1.3 2003/06/03 14:39:51 ho Exp $ */
+
+/*
+ * Copyright (c) 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+#include "sysdep.h"
+
+#include "util.h"
+
+int test_1 (char *, char *, int);
+
+int
+main (int argc, char *argv[])
+{
+ test_1 ("10.0.0.1", "10", 0);
+ test_1 ("10.0.0.1", "isakmp", 0);
+ test_1 ("10::1", "10", 0);
+ test_1 ("10::1", "isakmp", 0);
+ test_1 ("10.0x0.1", "10", -1);
+ test_1 ("10.0.0.1", "telnet", -1);
+ test_1 ("10::x:1", "10", -1);
+ test_1 ("10::1", "telnet", -1);
+ return 0;
+}
+
+int test_1 (char *address, char *port, int ok)
+{
+ struct sockaddr *sa;
+#ifdef DEBUG
+ struct sockaddr_in *sai;
+ struct sockaddr_in6 *sai6;
+ int i;
+#endif
+ int rv;
+
+ printf ("test_1 (\"%s\", \"%s\") ", address, port);
+ rv = text2sockaddr (address, port, &sa) == ok;
+ printf (rv ? "OK" : "FAIL");
+ printf ("\n");
+
+#ifdef DEBUG
+ printf ("af %d len %d ", sa->sa_family, sa->sa_len);
+ if (sa->sa_family == AF_INET)
+ {
+ sai = (struct sockaddr_in *)sa;
+ printf ("addr %08x port %d\n", ntohl (sai->sin_addr.s_addr),
+ ntohs (sai->sin_port));
+ }
+ else
+ {
+ sai6 = (struct sockaddr_in6 *)sa;
+ printf ("addr ");
+ for (i = 0; i < sizeof sai6->sin6_addr; i++)
+ printf ("%02x", sai6->sin6_addr.s6_addr[i]);
+ printf (" port %d\n", ntohs (sai6->sin6_port));
+ }
+#endif
+ return rv;
+}
diff --git a/keyexchange/isakmpd-20041012/regress/x509/.cvsignore b/keyexchange/isakmpd-20041012/regress/x509/.cvsignore
new file mode 100644
index 0000000..9863c98
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/x509/.cvsignore
@@ -0,0 +1,2 @@
+x509test
+obj
diff --git a/keyexchange/isakmpd-20041012/regress/x509/Makefile b/keyexchange/isakmpd-20041012/regress/x509/Makefile
new file mode 100644
index 0000000..2ce1e95
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/x509/Makefile
@@ -0,0 +1,95 @@
+# $OpenBSD: Makefile,v 1.14 2003/06/03 14:39:51 ho Exp $
+# $EOM: Makefile,v 1.16 2000/09/28 12:53:27 niklas Exp $
+
+#
+# Copyright (c) 1999 Niels Provos. All rights reserved.
+# Copyright (c) 1999, 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# Test X509
+
+# Enable this if you have a DNSSEC enabled OpenSSL
+#LIBLWRES= /usr/local/lib/liblwres.a
+
+PROG= x509test
+SRCS= x509test.c conf.c log.c libcrypto.c sysdep.c field.c util.c \
+ isakmp_fld.c ipsec_fld.c ipsec_num.c isakmp_num.c constants.c \
+ cert.c
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//'
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \
+ -DUSE_X509
+NOMAN=
+DEBUG= -g
+
+.if ${FEATURES:Mgmp} == "gmp"
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+.else
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
+.endif
+
+.include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep"
+
+.ifdef HAVE_DLOPEN
+X509= x509.c
+POLICY= policy.c
+CFLAGS+= -DHAVE_DLOPEN
+SRCS+= dyn.c
+.endif
+
+.ifdef USE_KEYNOTE
+USE_LIBCRYPTO= yes
+POLICY= policy.c
+LDADD+= -lkeynote -lm
+DPADD+= ${LIBKEYNOTE} ${LIBM}
+CFLAGS+= -DUSE_KEYNOTE
+.endif
+
+.ifdef USE_LIBCRYPTO
+X509= x509.c
+CFLAGS+= -DUSE_LIBCRYPTO
+LDADD+= -lcrypto ${LIBLWRES}
+DPADD+= ${LIBCRYPTO}
+.endif
+
+.if !defined (HAVE_DLOPEN) && !defined (USE_LIBCRYPTO) || !defined (USE_KEYNOTE)
+.BEGIN:
+
+PROG=
+.endif
+
+SRCS+= ${X509} ${POLICY}
+
+LDADD+= ${DESLIB}
+DPADD+= ${DESLIBDEP}
+
+.include <bsd.prog.mk>
diff --git a/keyexchange/isakmpd-20041012/regress/x509/x509test.c b/keyexchange/isakmpd-20041012/regress/x509/x509test.c
new file mode 100644
index 0000000..25b8bab
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/regress/x509/x509test.c
@@ -0,0 +1,291 @@
+/* $OpenBSD: x509test.c,v 1.22 2003/06/03 14:39:51 ho Exp $ */
+/* $EOM: x509test.c,v 1.9 2000/12/21 15:24:25 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * This program takes a certificate generated by ssleay and a key pair
+ * from rsakeygen. It reads the IP address from certificate.txt and
+ * includes this as subject alt name extension into the certifcate.
+ * The result gets written as new certificate that can be used by
+ * isakmpd.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "conf.h"
+#include "ipsec_num.h"
+#include "isakmp_fld.h"
+#include "libcrypto.h"
+#include "log.h"
+#include "math_mp.h"
+#include "x509.h"
+
+static int x509_check_subjectaltname (u_char *, u_int, X509 *);
+
+u_int32_t file_sz;
+
+#if 0
+/* XXX Currently unused. */
+static u_int8_t *
+open_file (char *name)
+{
+ int fd;
+ struct stat st;
+ u_int8_t *addr;
+
+ if (stat (name, &st) == -1)
+ log_fatal ("stat (\"%s\", &st)", name);
+ file_sz = st.st_size;
+ fd = open (name, O_RDONLY);
+ if (fd == -1)
+ log_fatal ("open (\"%s\", O_RDONLY)", name);
+ addr = mmap (0, file_sz, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
+ fd, 0);
+ if (addr == MAP_FAILED)
+ log_fatal ("mmap (0, %d, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,"
+ "%d, 0)", file_sz, fd);
+ close (fd);
+
+ return addr;
+}
+#endif
+
+/*
+ * Check that a certificate has a subjectAltName and that it matches our ID.
+ */
+static int
+x509_check_subjectaltname (u_char *id, u_int id_len, X509 *scert)
+{
+ u_int8_t *altname;
+ u_int32_t altlen;
+ int type, idtype, ret;
+
+ type = x509_cert_subjectaltname (scert, &altname, &altlen);
+ if (!type)
+ {
+ log_print ("x509_check_subjectaltname: can't access subjectAltName");
+ return 0;
+ }
+
+ /*
+ * Now that we have the X509 certicate in native form, get the
+ * subjectAltName extension and verify that it matches our ID.
+ */
+
+ /* XXX Get type of ID. */
+ idtype = id[0];
+ id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+ id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+
+ ret = 0;
+ switch (idtype)
+ {
+ case IPSEC_ID_IPV4_ADDR:
+ if (type == X509v3_IP_ADDR)
+ ret = 1;
+ break;
+ case IPSEC_ID_FQDN:
+ if (type == X509v3_DNS_NAME)
+ ret = 1;
+ break;
+ case IPSEC_ID_USER_FQDN:
+ if (type == X509v3_RFC_NAME)
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ if (!ret)
+ {
+ LOG_DBG ((LOG_CRYPTO, 50,
+ "x509_check_subjectaltname: "
+ "our ID type (%d) does not match X509 cert ID type (%d)",
+ idtype, type));
+ return 0;
+ }
+
+ if (altlen != id_len || memcmp (altname, id, id_len) != 0)
+ {
+ LOG_DBG ((LOG_CRYPTO, 50,
+ "x509_check_subjectaltname: "
+ "our ID does not match X509 cert ID"));
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+main (int argc, char *argv[])
+{
+ RSA *pub_key, *priv_key;
+ X509 *cert;
+ BIO *certfile, *keyfile;
+ EVP_PKEY *pkey_pub;
+ u_char ipaddr[6];
+ struct in_addr saddr;
+ char enc[256], dec[256];
+ u_int8_t idpayload[8];
+ int err, len;
+
+ if (argc < 3 || argc > 4)
+ {
+ fprintf (stderr, "usage: x509test private-key certificate ip-address\n");
+ exit (1);
+ }
+
+ /*
+ * X509_verify will fail, as will all other functions that call
+ * EVP_get_digest_byname.
+ */
+
+ libcrypto_init ();
+
+ printf ("Reading private key %s\n", argv[1]);
+ keyfile = BIO_new (BIO_s_file ());
+ if (BIO_read_filename (keyfile, argv[1]) == -1)
+ {
+ perror ("read");
+ exit (1);
+ }
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL, NULL);
+#else
+ priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL);
+#endif
+ BIO_free (keyfile);
+ if (priv_key == NULL)
+ {
+ printf("PEM_read_bio_RSAPrivateKey () failed\n");
+ exit (1);
+ }
+
+ /* Use a certificate created by ssleay. */
+ printf ("Reading ssleay created certificate %s\n", argv[2]);
+ certfile = BIO_new (BIO_s_file ());
+ if (BIO_read_filename (certfile, argv[2]) == -1)
+ {
+ perror ("read");
+ exit (1);
+ }
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ cert = PEM_read_bio_X509 (certfile, NULL, NULL, NULL);
+#else
+ cert = PEM_read_bio_X509 (certfile, NULL, NULL);
+#endif
+ BIO_free (certfile);
+ if (cert == NULL)
+ {
+ printf("PEM_read_bio_X509 () failed\n");
+ exit (1);
+ }
+
+ pkey_pub = X509_get_pubkey (cert);
+ /* XXX Violation of the interface? */
+ pub_key = pkey_pub->pkey.rsa;
+ if (pub_key == NULL)
+ {
+ exit (1);
+ }
+
+ printf ("Testing RSA keys: ");
+
+ err = 0;
+ strlcpy (dec, "Eine kleine Testmeldung", 256);
+ if ((len = RSA_private_encrypt (strlen (dec), dec, enc, priv_key,
+ RSA_PKCS1_PADDING)) == -1)
+
+ printf ("SIGN FAILED ");
+ else
+ err = RSA_public_decrypt (len, enc, dec, pub_key, RSA_PKCS1_PADDING);
+
+ if (err == -1 || strcmp (dec, "Eine kleine Testmeldung"))
+ printf ("SIGN/VERIFY FAILED");
+ else
+ printf ("OKAY");
+ printf ("\n");
+
+
+ printf ("Validate SIGNED: ");
+ err = X509_verify (cert, pkey_pub);
+ printf ("X509 verify: %d ", err);
+ if (err == -1)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+ printf ("\n");
+
+ if (argc == 4)
+ {
+ printf ("Verifying extension: ");
+ if (inet_aton (argv[3], &saddr) == 0)
+ {
+ printf ("inet_aton () failed\n");
+ exit (1);
+ }
+
+ saddr.s_addr = htonl (saddr.s_addr);
+ ipaddr[0] = 0x87;
+ ipaddr[1] = 0x04;
+ ipaddr[2] = saddr.s_addr >> 24;
+ ipaddr[3] = (saddr.s_addr >> 16) & 0xff;
+ ipaddr[4] = (saddr.s_addr >> 8) & 0xff;
+ ipaddr[5] = saddr.s_addr & 0xff;
+ bzero (idpayload, sizeof idpayload);
+ idpayload[0] = IPSEC_ID_IPV4_ADDR;
+ bcopy (ipaddr + 2, idpayload + 4, 4);
+
+ if (!x509_check_subjectaltname (idpayload, sizeof idpayload, cert))
+ printf("FAILED ");
+ else
+ printf("OKAY ");
+ printf ("\n");
+ }
+
+ return 1;
+}
diff --git a/keyexchange/isakmpd-20041012/sa.c b/keyexchange/isakmpd-20041012/sa.c
new file mode 100644
index 0000000..14c7857
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sa.c
@@ -0,0 +1,1247 @@
+/* $OpenBSD: sa.c,v 1.86 2004/08/10 15:59:10 ho Exp $ */
+/* $EOM: sa.c,v 1.112 2000/12/12 00:22:52 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2003, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined (USE_KEYNOTE) || defined (USE_POLICY)
+#include <regex.h>
+#include <keynote.h>
+#endif /* USE_KEYNOTE || USE_POLICY */
+
+#include "sysdep.h"
+
+#include "attribute.h"
+#include "conf.h"
+#include "connection.h"
+#include "cookie.h"
+#include "doi.h"
+#include "exchange.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#include "monitor.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+#include "cert.h"
+#include "policy.h"
+#include "key.h"
+#include "ipsec.h"
+#include "ipsec_num.h"
+
+/* Initial number of bits from the cookies used as hash. */
+#define INITIAL_BUCKET_BITS 6
+
+/*
+ * Don't try to use more bits than this as a hash.
+ * We only XOR 16 bits so going above that means changing the code below
+ * too.
+ */
+#define MAX_BUCKET_BITS 16
+
+#if 0
+static void sa_resize(void);
+#endif
+static void sa_soft_expire(void *);
+static void sa_hard_expire(void *);
+
+static LIST_HEAD(sa_list, sa) *sa_tab;
+
+/* Works both as a maximum index and a mask. */
+static int bucket_mask;
+
+void
+sa_init(void)
+{
+ int i;
+
+ bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1;
+ sa_tab = malloc((bucket_mask + 1) * sizeof(struct sa_list));
+ if (!sa_tab)
+ log_fatal("sa_init: malloc (%lu) failed",
+ (bucket_mask + 1) * (unsigned long)sizeof(struct sa_list));
+ for (i = 0; i <= bucket_mask; i++)
+ LIST_INIT(&sa_tab[i]);
+}
+
+#if 0
+/* XXX We don't yet resize. */
+static void
+sa_resize(void)
+{
+ int new_mask = (bucket_mask + 1) * 2 - 1;
+ int i;
+ struct sa_list *new_tab;
+
+ new_tab = realloc(sa_tab, (new_mask + 1) * sizeof(struct sa_list));
+ if (!new_tab)
+ return;
+ sa_tab = new_tab;
+ for (i = bucket_mask + 1; i <= new_mask; i++)
+ LIST_INIT(&sa_tab[i]);
+ bucket_mask = new_mask;
+
+ /* XXX Rehash existing entries. */
+}
+#endif
+
+/* Lookup an SA with the help from a user-supplied checking function. */
+struct sa *
+sa_find(int (*check) (struct sa*, void *), void *arg)
+{
+ int i;
+ struct sa *sa;
+
+ for (i = 0; i <= bucket_mask; i++)
+ for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link))
+ if (check(sa, arg)) {
+ LOG_DBG((LOG_SA, 90, "sa_find: return SA %p",
+ sa));
+ return sa;
+ }
+ LOG_DBG((LOG_SA, 90, "sa_find: no SA matched query"));
+ return 0;
+}
+
+/* Check if SA is an ISAKMP SA with an initiator cookie equal to ICOOKIE. */
+static int
+sa_check_icookie(struct sa *sa, void *icookie)
+{
+ return sa->phase == 1 &&
+ memcmp(sa->cookies, icookie, ISAKMP_HDR_ICOOKIE_LEN) == 0;
+}
+
+/* Lookup an ISAKMP SA out of just the initiator cookie. */
+struct sa *
+sa_lookup_from_icookie(u_int8_t *cookie)
+{
+ return sa_find(sa_check_icookie, cookie);
+}
+
+struct name_phase_arg {
+ char *name;
+ u_int8_t phase;
+};
+
+/* Check if SA has the name and phase given by V_ARG. */
+static int
+sa_check_name_phase(struct sa *sa, void *v_arg)
+{
+ struct name_phase_arg *arg = v_arg;
+
+ return sa->name && strcasecmp(sa->name, arg->name) == 0 &&
+ sa->phase == arg->phase && !(sa->flags & SA_FLAG_REPLACED);
+}
+
+/* Lookup an SA by name, case-independent, and phase. */
+struct sa *
+sa_lookup_by_name(char *name, int phase)
+{
+ struct name_phase_arg arg;
+
+ arg.name = name;
+ arg.phase = phase;
+ return sa_find(sa_check_name_phase, &arg);
+}
+
+struct addr_arg {
+ struct sockaddr *addr;
+ socklen_t len;
+ int phase;
+ int flags;
+};
+
+/*
+ * Check if SA is ready and has a peer with an address equal the one given
+ * by V_ADDR. Furthermore if we are searching for a specific phase, check
+ * that too.
+ */
+static int
+sa_check_peer(struct sa *sa, void *v_addr)
+{
+ struct addr_arg *addr = v_addr;
+ struct sockaddr *dst;
+
+ if (!sa->transport || (sa->flags & SA_FLAG_READY) == 0 ||
+ (addr->phase && addr->phase != sa->phase))
+ return 0;
+
+ sa->transport->vtbl->get_dst(sa->transport, &dst);
+ return sysdep_sa_len(dst) == addr->len &&
+ memcmp(dst, addr->addr, sysdep_sa_len(dst)) == 0;
+}
+
+struct dst_isakmpspi_arg {
+ struct sockaddr *dst;
+ u_int8_t *spi; /* must be ISAKMP_SPI_SIZE octets */
+};
+
+/*
+ * Check if SA matches what we are asking for through V_ARG. It has to
+ * be a finished phaes 1 (ISAKMP) SA.
+ */
+static int
+isakmp_sa_check(struct sa *sa, void *v_arg)
+{
+ struct dst_isakmpspi_arg *arg = v_arg;
+ struct sockaddr *dst, *src;
+
+ if (sa->phase != 1 || !(sa->flags & SA_FLAG_READY))
+ return 0;
+
+ /* verify address is either src or dst for this sa */
+ sa->transport->vtbl->get_dst(sa->transport, &dst);
+ sa->transport->vtbl->get_src(sa->transport, &src);
+ if (memcmp(src, arg->dst, sysdep_sa_len(src)) &&
+ memcmp(dst, arg->dst, sysdep_sa_len(dst)))
+ return 0;
+
+ /* match icookie+rcookie against spi */
+ if (memcmp(sa->cookies, arg->spi, ISAKMP_HDR_COOKIES_LEN) == 0)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Find an ISAKMP SA with a "name" of DST & SPI.
+ */
+struct sa *
+sa_lookup_isakmp_sa(struct sockaddr *dst, u_int8_t *spi)
+{
+ struct dst_isakmpspi_arg arg;
+
+ arg.dst = dst;
+ arg.spi = spi;
+
+ return sa_find(isakmp_sa_check, &arg);
+}
+
+/* Lookup a ready SA by the peer's address. */
+struct sa *
+sa_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen)
+{
+ struct addr_arg arg;
+
+ arg.addr = dst;
+ arg.len = dstlen;
+ arg.phase = 0;
+
+ return sa_find(sa_check_peer, &arg);
+}
+
+/* Lookup a ready ISAKMP SA given its peer address. */
+struct sa *
+sa_isakmp_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen)
+{
+ struct addr_arg arg;
+
+ arg.addr = dst;
+ arg.len = dstlen;
+ arg.phase = 1;
+
+ return sa_find(sa_check_peer, &arg);
+}
+
+int
+sa_enter(struct sa *sa)
+{
+ u_int16_t bucket = 0;
+ int i;
+ u_int8_t *cp;
+
+ /* XXX We might resize if we are crossing a certain threshold */
+
+ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2) {
+ cp = sa->cookies + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2) {
+ cp = sa->message_id + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ bucket &= bucket_mask;
+ LIST_INSERT_HEAD(&sa_tab[bucket], sa, link);
+ sa_reference(sa);
+ LOG_DBG((LOG_SA, 70, "sa_enter: SA %p added to SA list", sa));
+ return 1;
+}
+
+/*
+ * Lookup the SA given by the header fields MSG. PHASE2 is false when
+ * looking for phase 1 SAa and true otherwise.
+ */
+struct sa *
+sa_lookup_by_header(u_int8_t *msg, int phase2)
+{
+ return sa_lookup(msg + ISAKMP_HDR_COOKIES_OFF,
+ phase2 ? msg + ISAKMP_HDR_MESSAGE_ID_OFF : 0);
+}
+
+/*
+ * Lookup the SA given by the COOKIES and possibly the MESSAGE_ID unless
+ * a null pointer, meaning we are looking for phase 1 SAs.
+ */
+struct sa *
+sa_lookup(u_int8_t *cookies, u_int8_t *message_id)
+{
+ u_int16_t bucket = 0;
+ int i;
+ struct sa *sa;
+ u_int8_t *cp;
+
+ /*
+ * We use the cookies to get bits to use as an index into sa_tab, as at
+ * least one (our cookie) is a good hash, xoring all the bits, 16 at a
+ * time, and then masking, should do. Doing it this way means we can
+ * validate cookies very fast thus delimiting the effects of "Denial of
+ * service"-attacks using packet flooding.
+ */
+ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2) {
+ cp = cookies + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ if (message_id)
+ for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2) {
+ cp = message_id + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ bucket &= bucket_mask;
+ for (sa = LIST_FIRST(&sa_tab[bucket]);
+ sa && (memcmp(cookies, sa->cookies, ISAKMP_HDR_COOKIES_LEN) != 0
+ || (message_id && memcmp(message_id, sa->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN) != 0)
+ || (!message_id && !zero_test(sa->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN)));
+ sa = LIST_NEXT(sa, link))
+ ;
+
+ return sa;
+}
+
+/* Create an SA. */
+int
+sa_create(struct exchange *exchange, struct transport *t)
+{
+ struct sa *sa;
+
+ /*
+ * We want the SA zeroed for sa_free to be able to find out what fields
+ * have been filled-in.
+ */
+ sa = calloc(1, sizeof *sa);
+ if (!sa) {
+ log_error("sa_create: calloc (1, %lu) failed",
+ (unsigned long)sizeof *sa);
+ return -1;
+ }
+ sa->transport = t;
+ if (t)
+ transport_reference(t);
+ sa->phase = exchange->phase;
+ memcpy(sa->cookies, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ memcpy(sa->message_id, exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ sa->doi = exchange->doi;
+ sa->policy_id = -1;
+
+ if (sa->doi->sa_size) {
+ /*
+ * Allocate the DOI-specific structure and initialize it to
+ * zeroes.
+ */
+ sa->data = calloc(1, sa->doi->sa_size);
+ if (!sa->data) {
+ log_error("sa_create: calloc (1, %lu) failed",
+ (unsigned long)sa->doi->sa_size);
+ free(sa);
+ return -1;
+ }
+ }
+ TAILQ_INIT(&sa->protos);
+
+ sa_enter(sa);
+ TAILQ_INSERT_TAIL(&exchange->sa_list, sa, next);
+ sa_reference(sa);
+
+ LOG_DBG((LOG_SA, 60,
+ "sa_create: sa %p phase %d added to exchange %p (%s)", sa,
+ sa->phase, exchange,
+ exchange->name ? exchange->name : "<unnamed>"));
+ return 0;
+}
+
+/*
+ * Dump the internal state of SA to the report channel, with HEADER
+ * prepended to each line.
+ */
+void
+sa_dump(int cls, int level, char *header, struct sa *sa)
+{
+ struct proto *proto;
+ char spi_header[80];
+ int i;
+
+ LOG_DBG((cls, level, "%s: %p %s phase %d doi %d flags 0x%x", header,
+ sa, sa->name ? sa->name : "<unnamed>", sa->phase, sa->doi->id,
+ sa->flags));
+ LOG_DBG((cls, level, "%s: icookie %08x%08x rcookie %08x%08x", header,
+ decode_32(sa->cookies), decode_32(sa->cookies + 4),
+ decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)));
+ LOG_DBG((cls, level, "%s: msgid %08x refcnt %d", header,
+ decode_32(sa->message_id), sa->refcnt));
+ LOG_DBG((cls, level, "%s: life secs %llu kb %llu", header, sa->seconds,
+ sa->kilobytes));
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link)) {
+ LOG_DBG((cls, level, "%s: suite %d proto %d", header,
+ proto->no, proto->proto));
+ LOG_DBG((cls, level,
+ "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p",
+ header, proto->spi_sz[0], proto->spi[0], proto->spi_sz[1],
+ proto->spi[1]));
+ LOG_DBG((cls, level, "%s: %s, %s", header,
+ !sa->doi ? "<nodoi>" :
+ sa->doi->decode_ids("initiator id: %s, responder id: %s",
+ sa->id_i, sa->id_i_len,
+ sa->id_r, sa->id_r_len, 0),
+ !sa->transport ? "<no transport>" :
+ sa->transport->vtbl->decode_ids(sa->transport)));
+ for (i = 0; i < 2; i++)
+ if (proto->spi[i]) {
+ snprintf(spi_header, sizeof spi_header,
+ "%s: spi[%d]", header, i);
+ LOG_DBG_BUF((cls, level, spi_header,
+ proto->spi[i], proto->spi_sz[i]));
+ }
+ }
+}
+
+/*
+ * Display the SA's two SPI values.
+ */
+static void
+report_spi(FILE *fd, const u_int8_t *buf, size_t sz, int spi)
+{
+#define SBUFSZ (2 * 32 + 9)
+ char s[SBUFSZ];
+ size_t i, j;
+
+ for (i = j = 0; i < sz;) {
+ snprintf(s + j, sizeof s - j, "%02x", buf[i++]);
+ j += 2;
+ if (i % 4 == 0) {
+ if (i % 32 == 0) {
+ s[j] = '\0';
+ fprintf(fd, "%s", s);
+ j = 0;
+ } else
+ s[j++] = ' ';
+ }
+ }
+
+ if (j) {
+ s[j] = '\0';
+ fprintf(fd, "SPI %d: %s\n", spi, s);
+ }
+}
+
+/*
+ * Display the transform names to file.
+ * Structure is taken from pf_key_v2.c, pf_key_v2_set_spi.
+ * Transform names are taken from /usr/src/sys/crypto/xform.c.
+ */
+static void
+report_proto(FILE *fd, struct proto *proto)
+{
+ struct ipsec_proto *iproto = proto->data;
+ int keylen, hashlen;
+
+ switch (proto->proto) {
+ case IPSEC_PROTO_IPSEC_ESP:
+ keylen = ipsec_esp_enckeylength(proto);
+ hashlen = ipsec_esp_authkeylength(proto);
+ fprintf(fd, "Transform: IPsec ESP\n");
+ fprintf(fd, "Encryption key length: %d\n", keylen);
+ fprintf(fd, "Authentication key length: %d\n", hashlen);
+
+ fprintf(fd, "Encryption algorithm: ");
+ switch (proto->id) {
+ case IPSEC_ESP_DES:
+ case IPSEC_ESP_DES_IV32:
+ case IPSEC_ESP_DES_IV64:
+ fprintf(fd, "DES\n");
+ break;
+
+ case IPSEC_ESP_3DES:
+ fprintf(fd, "3DES\n");
+ break;
+
+ case IPSEC_ESP_AES:
+ fprintf(fd, "AES-128 (CBC)\n");
+ break;
+
+ case IPSEC_ESP_AES_128_CTR:
+ fprintf(fd, "AES-128 (CTR)\n");
+ break;
+
+ case IPSEC_ESP_CAST:
+ fprintf(fd, "Cast-128\n");
+ break;
+
+ case IPSEC_ESP_BLOWFISH:
+ fprintf(fd, "Blowfish\n");
+ break;
+
+ default:
+ fprintf(fd, "unknown (%d)\n", proto->id);
+ }
+
+ fprintf(fd, "Authentication algorithm: ");
+ switch (iproto->auth) {
+ case IPSEC_AUTH_HMAC_MD5:
+ fprintf(fd, "HMAC-MD5\n");
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA:
+ fprintf(fd, "HMAC-SHA1\n");
+ break;
+
+ case IPSEC_AUTH_HMAC_RIPEMD:
+ fprintf(fd, "HMAC-RIPEMD-160\n");
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_256:
+ fprintf(fd, "HMAC-SHA2-256\n");
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_384:
+ fprintf(fd, "HMAC-SHA2-384\n");
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA2_512:
+ fprintf(fd, "HMAC-SHA2-512\n");
+ break;
+
+ case IPSEC_AUTH_DES_MAC:
+ case IPSEC_AUTH_KPDK:
+ /* XXX We should be supporting KPDK */
+ fprintf(fd, "unknown (%d)", iproto->auth);
+ break;
+
+ default:
+ fprintf(fd, "none\n");
+ }
+ break;
+
+ case IPSEC_PROTO_IPSEC_AH:
+ hashlen = ipsec_ah_keylength(proto);
+ fprintf(fd, "Transform: IPsec AH\n");
+ fprintf(fd, "Encryption not used.\n");
+ fprintf(fd, "Authentication key length: %d\n", hashlen);
+
+ fprintf(fd, "Authentication algorithm: ");
+ switch (proto->id) {
+ case IPSEC_AH_MD5:
+ fprintf(fd, "HMAC-MD5\n");
+ break;
+
+ case IPSEC_AH_SHA:
+ fprintf(fd, "HMAC-SHA1\n");
+ break;
+
+ case IPSEC_AH_RIPEMD:
+ fprintf(fd, "HMAC-RIPEMD-160\n");
+ break;
+
+ case IPSEC_AH_SHA2_256:
+ fprintf(fd, "HMAC-SHA2-256\n");
+ break;
+
+ case IPSEC_AH_SHA2_384:
+ fprintf(fd, "HMAC-SHA2-384\n");
+ break;
+
+ case IPSEC_AH_SHA2_512:
+ fprintf(fd, "HMAC-SHA2-512\n");
+ break;
+
+ default:
+ fprintf(fd, "unknown (%d)", proto->id);
+ }
+ break;
+
+ default:
+ fprintf(fd, "report_proto: invalid proto %d\n", proto->proto);
+ }
+}
+
+/* Report all the SAs to the report channel. */
+void
+sa_report(void)
+{
+ struct sa *sa;
+ int i;
+
+ for (i = 0; i <= bucket_mask; i++)
+ for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link))
+ sa_dump(LOG_REPORT, 0, "sa_report", sa);
+}
+
+
+/*
+ * Print an SA's connection details to file SA_FILE.
+ */
+static void
+sa_dump_all(FILE *fd, struct sa *sa)
+{
+ struct proto *proto;
+ int i;
+
+ /* SA name and phase. */
+ fprintf(fd, "SA name: %s", sa->name ? sa->name : "<unnamed>");
+ fprintf(fd, " (Phase %d)\n", sa->phase);
+
+ /* Source and destination IPs. */
+ fprintf(fd, sa->transport == NULL ? "<no transport>" :
+ sa->transport->vtbl->decode_ids(sa->transport));
+ fprintf(fd, "\n");
+
+ /* Transform information. */
+ for (proto = TAILQ_FIRST(&sa->protos); proto;
+ proto = TAILQ_NEXT(proto, link)) {
+ /* SPI values. */
+ for (i = 0; i < 2; i++)
+ if (proto->spi[i])
+ report_spi(fd, proto->spi[i], proto->spi_sz[i],
+ i);
+ else
+ fprintf(fd, "SPI %d not defined.", i);
+
+ /* Proto values. */
+ report_proto(fd, proto);
+
+ /* SA separator. */
+ fprintf(fd, "\n");
+ }
+}
+
+/* Report info of all SAs to file 'fd'. */
+void
+sa_report_all(FILE *fd)
+{
+ struct sa *sa;
+ int i;
+
+ for (i = 0; i <= bucket_mask; i++)
+ for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link))
+ if (sa->phase == 1)
+ fprintf(fd, "SA name: none (phase 1)\n\n");
+ else
+ sa_dump_all(fd, sa);
+}
+
+/* Free the protocol structure pointed to by PROTO. */
+void
+proto_free(struct proto *proto)
+{
+ struct proto_attr *pa;
+ struct sa *sa = proto->sa;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (proto->spi[i]) {
+ if (sa->doi->delete_spi)
+ sa->doi->delete_spi(sa, proto, i);
+ free(proto->spi[i]);
+ }
+ TAILQ_REMOVE(&sa->protos, proto, link);
+ if (proto->data) {
+ if (sa->doi && sa->doi->free_proto_data)
+ sa->doi->free_proto_data(proto->data);
+ free(proto->data);
+ }
+ if (proto->xf_cnt)
+ while ((pa = TAILQ_FIRST(&proto->xfs)) != NULL) {
+ if (pa->attrs)
+ free(pa->attrs);
+ TAILQ_REMOVE(&proto->xfs, pa, next);
+ free(pa);
+ }
+
+ LOG_DBG((LOG_SA, 90, "proto_free: freeing %p", proto));
+ free(proto);
+}
+
+/* Release all resources this SA is using. */
+void
+sa_free(struct sa *sa)
+{
+ if (sa->death) {
+ timer_remove_event(sa->death);
+ sa->death = 0;
+ sa->refcnt--;
+ }
+ if (sa->soft_death) {
+ timer_remove_event(sa->soft_death);
+ sa->soft_death = 0;
+ sa->refcnt--;
+ }
+ sa_remove(sa);
+}
+
+/* Remove the SA from the hash table of live SAs. */
+void
+sa_remove(struct sa *sa)
+{
+ LIST_REMOVE(sa, link);
+ LOG_DBG((LOG_SA, 70, "sa_remove: SA %p removed from SA list", sa));
+ sa_release(sa);
+}
+
+/* Raise the reference count of SA. */
+void
+sa_reference(struct sa *sa)
+{
+ sa->refcnt++;
+ LOG_DBG((LOG_SA, 80, "sa_reference: SA %p now has %d references",
+ sa, sa->refcnt));
+}
+
+/* Release a reference to SA. */
+void
+sa_release(struct sa *sa)
+{
+ struct cert_handler *handler;
+ struct proto *proto;
+
+ LOG_DBG((LOG_SA, 80, "sa_release: SA %p had %d references",
+ sa, sa->refcnt));
+
+ if (--sa->refcnt)
+ return;
+
+ LOG_DBG((LOG_SA, 60, "sa_release: freeing SA %p", sa));
+
+ while ((proto = TAILQ_FIRST(&sa->protos)) != 0)
+ proto_free(proto);
+ if (sa->data) {
+ if (sa->doi && sa->doi->free_sa_data)
+ sa->doi->free_sa_data(sa->data);
+ free(sa->data);
+ }
+ if (sa->id_i)
+ free(sa->id_i);
+ if (sa->id_r)
+ free(sa->id_r);
+ if (sa->recv_cert) {
+ handler = cert_get(sa->recv_certtype);
+ if (handler)
+ handler->cert_free(sa->recv_cert);
+ }
+ if (sa->sent_cert) {
+ handler = cert_get(sa->sent_certtype);
+ if (handler)
+ handler->cert_free(sa->sent_cert);
+ }
+ if (sa->recv_key)
+ key_free(sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC,
+ sa->recv_key);
+ if (sa->keynote_key)
+ free(sa->keynote_key); /* This is just a string */
+#if defined (USE_POLICY) || defined (USE_KEYNOTE)
+ if (sa->policy_id != -1)
+ kn_close(sa->policy_id);
+#endif
+ if (sa->name)
+ free(sa->name);
+ if (sa->keystate)
+ free(sa->keystate);
+#if defined (USE_NAT_TRAVERSAL)
+ if (sa->nat_t_keepalive)
+ timer_remove_event(sa->nat_t_keepalive);
+#endif
+#if defined (USE_DPD)
+ if (sa->dpd_event)
+ timer_remove_event(sa->dpd_event);
+#endif
+ if (sa->transport)
+ transport_release(sa->transport);
+ free(sa);
+}
+
+/*
+ * Rehash the ISAKMP SA this MSG is negotiating with the responder cookie
+ * filled in.
+ */
+void
+sa_isakmp_upgrade(struct message *msg)
+{
+ struct sa *sa = TAILQ_FIRST(&msg->exchange->sa_list);
+
+ sa_remove(sa);
+ GET_ISAKMP_HDR_RCOOKIE(msg->iov[0].iov_base,
+ sa->cookies + ISAKMP_HDR_ICOOKIE_LEN);
+
+ /*
+ * We don't install a transport in the initiator case as we don't know
+ * what local address will be chosen. Do it now instead.
+ */
+ sa->transport = msg->transport;
+ transport_reference(sa->transport);
+ sa_enter(sa);
+}
+
+#define ATTRS_SIZE (IKE_ATTR_BLOCK_SIZE + 1) /* XXX Should be dynamic. */
+
+struct attr_validation_state {
+ u_int8_t *attrp[ATTRS_SIZE];
+ u_int8_t checked[ATTRS_SIZE];
+ int phase; /* IKE (1) or IPSEC (2) attrs? */
+ int mode; /* 0 = 'load', 1 = check */
+};
+
+/* Validate an attribute. Return 0 on match. */
+static int
+sa_validate_xf_attrs(u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *arg)
+{
+ struct attr_validation_state *avs =
+ (struct attr_validation_state *)arg;
+
+ LOG_DBG((LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d "
+ "len %d", avs->phase, avs->mode, type, len));
+
+ /* Make sure the phase and type are valid. */
+ if (avs->phase == 1) {
+ if (type < IKE_ATTR_ENCRYPTION_ALGORITHM ||
+ type > IKE_ATTR_BLOCK_SIZE)
+ return 1;
+ } else if (avs->phase == 2) {
+ if (type < IPSEC_ATTR_SA_LIFE_TYPE ||
+ type > IPSEC_ATTR_ECN_TUNNEL)
+ return 1;
+ } else
+ return 1;
+
+ if (avs->mode == 0) { /* Load attrs. */
+ avs->attrp[type] = value;
+ return 0;
+ }
+ /* Checking for a missing attribute is an immediate failure. */
+ if (!avs->attrp[type])
+ return 1;
+
+ /* Match the loaded attribute against this one, mark it as checked. */
+ avs->checked[type]++;
+ return memcmp(avs->attrp[type], value, len);
+}
+
+/*
+ * This function is used to validate the returned proposal (protection suite)
+ * we get from the responder against a proposal we sent. Only run as initiator.
+ * We return 0 if a match is found (in any transform of this proposal), 1
+ * otherwise. Also see note in sa_add_transform() below.
+ */
+static int
+sa_validate_proto_xf(struct proto *match, struct payload *xf, int phase)
+{
+ struct attr_validation_state *avs;
+ struct proto_attr *pa;
+ int found = 0;
+ size_t i;
+ u_int8_t xf_id;
+
+ if (!match->xf_cnt)
+ return 0;
+
+ if (match->proto != GET_ISAKMP_PROP_PROTO(xf->context->p)) {
+ LOG_DBG((LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) "
+ "protocol mismatch", match, match->no));
+ return 1;
+ }
+ avs = (struct attr_validation_state *)calloc(1, sizeof *avs);
+ if (!avs) {
+ log_error("sa_validate_proto_xf: calloc (1, %lu)",
+ (unsigned long)sizeof *avs);
+ return 1;
+ }
+ avs->phase = phase;
+
+ /* Load the "proposal candidate" attribute set. */
+ (void) attribute_map(xf->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH(xf->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ sa_validate_xf_attrs, avs);
+ xf_id = GET_ISAKMP_TRANSFORM_ID(xf->p);
+
+ /* Check against the transforms we suggested. */
+ avs->mode++;
+ for (pa = TAILQ_FIRST(&match->xfs); pa && !found;
+ pa = TAILQ_NEXT(pa, next)) {
+ if (xf_id != GET_ISAKMP_TRANSFORM_ID(pa->attrs))
+ continue;
+
+ memset(avs->checked, 0, sizeof avs->checked);
+ if (attribute_map(pa->attrs + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ pa->len - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ sa_validate_xf_attrs, avs) == 0)
+ found++;
+
+ LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: attr_map "
+ "xf %p proto %p pa %p found %d", xf, match, pa, found));
+
+ if (!found)
+ continue;
+
+ /*
+ * Require all attributes present and checked. XXX perhaps
+ * not?
+ */
+ for (i = 0; i < sizeof avs->checked; i++)
+ if (avs->attrp[i] && !avs->checked[i])
+ found = 0;
+
+ LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: req_attr "
+ "xf %p proto %p pa %p found %d", xf, match, pa, found));
+ }
+ free(avs);
+ return found ? 0 : 1;
+}
+
+/*
+ * Register the chosen transform XF into SA. As a side effect set PROTOP
+ * to point at the corresponding proto structure. INITIATOR is true if we
+ * are the initiator.
+ */
+int
+sa_add_transform(struct sa *sa, struct payload *xf, int initiator,
+ struct proto **protop)
+{
+ struct proto *proto;
+ struct payload *prop = xf->context;
+
+ *protop = 0;
+ if (!initiator) {
+ proto = calloc(1, sizeof *proto);
+ if (!proto)
+ log_error("sa_add_transform: calloc (1, %lu) failed",
+ (unsigned long)sizeof *proto);
+ } else {
+ /*
+ * RFC 2408, section 4.2 states the responder SHOULD use the
+ * proposal number from the initiator (i.e us), in it's
+ * selected proposal to make this lookup easier. Most vendors
+ * follow this. One noted exception is the CiscoPIX (and
+ * perhaps other Cisco products).
+ *
+ * We start by matching on the proposal number, as before.
+ */
+ for (proto = TAILQ_FIRST(&sa->protos);
+ proto && proto->no != GET_ISAKMP_PROP_NO(prop->p);
+ proto = TAILQ_NEXT(proto, link))
+ ;
+ /*
+ * If we did not find a match, search through all proposals
+ * and xforms.
+ */
+ if (!proto || sa_validate_proto_xf(proto, xf, sa->phase) != 0)
+ for (proto = TAILQ_FIRST(&sa->protos);
+ proto && sa_validate_proto_xf(proto, xf,
+ sa->phase) != 0;
+ proto = TAILQ_NEXT(proto, link))
+ ;
+ }
+ if (!proto)
+ return -1;
+ *protop = proto;
+
+ /* Allocate DOI-specific part. */
+ if (!initiator) {
+ proto->data = calloc(1, sa->doi->proto_size);
+ if (!proto->data) {
+ log_error("sa_add_transform: calloc (1, %lu) failed",
+ (unsigned long)sa->doi->proto_size);
+ goto cleanup;
+ }
+ }
+ proto->no = GET_ISAKMP_PROP_NO(prop->p);
+ proto->proto = GET_ISAKMP_PROP_PROTO(prop->p);
+ proto->spi_sz[0] = GET_ISAKMP_PROP_SPI_SZ(prop->p);
+ if (proto->spi_sz[0]) {
+ proto->spi[0] = malloc(proto->spi_sz[0]);
+ if (!proto->spi[0])
+ goto cleanup;
+ memcpy(proto->spi[0], prop->p + ISAKMP_PROP_SPI_OFF,
+ proto->spi_sz[0]);
+ }
+ proto->chosen = xf;
+ proto->sa = sa;
+ proto->id = GET_ISAKMP_TRANSFORM_ID(xf->p);
+ if (!initiator)
+ TAILQ_INSERT_TAIL(&sa->protos, proto, link);
+
+ /* Let the DOI get at proto for initializing its own data. */
+ if (sa->doi->proto_init)
+ sa->doi->proto_init(proto, 0);
+
+ LOG_DBG((LOG_SA, 80,
+ "sa_add_transform: "
+ "proto %p no %d proto %d chosen %p sa %p id %d",
+ proto, proto->no, proto->proto, proto->chosen, proto->sa,
+ proto->id));
+
+ return 0;
+
+cleanup:
+ if (!initiator) {
+ if (proto->data)
+ free(proto->data);
+ free(proto);
+ }
+ *protop = 0;
+ return -1;
+}
+
+/* Delete an SA. Tell the peer if NOTIFY is set. */
+void
+sa_delete(struct sa *sa, int notify)
+{
+ /* Don't bother notifying of Phase 1 SA deletes. */
+ if (sa->phase != 1 && notify)
+ message_send_delete(sa);
+ sa_free(sa);
+}
+
+
+/* Teardown all SAs. */
+void
+sa_teardown_all(void)
+{
+ int i;
+ struct sa *sa, *next = 0;
+
+ LOG_DBG((LOG_SA, 70, "sa_teardown_all:"));
+ /* Get Phase 2 SAs. */
+ for (i = 0; i <= bucket_mask; i++)
+ for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = next) {
+ next = LIST_NEXT(sa, link);
+ if (sa->phase == 2) {
+ /*
+ * Teardown the phase 2 SAs by name, similar
+ * to ui_teardown.
+ */
+ LOG_DBG((LOG_SA, 70,
+ "sa_teardown_all: tearing down SA %s",
+ sa->name));
+ connection_teardown(sa->name);
+ sa_delete(sa, 1);
+ }
+ }
+}
+
+/*
+ * This function will get called when we are closing in on the death time of SA
+ */
+static void
+sa_soft_expire(void *v_sa)
+{
+ struct sa *sa = v_sa;
+
+ sa->soft_death = 0;
+ sa_release(sa);
+
+ if ((sa->flags & (SA_FLAG_STAYALIVE | SA_FLAG_REPLACED)) ==
+ SA_FLAG_STAYALIVE)
+ exchange_establish(sa->name, 0, 0);
+ else
+ /*
+ * Start to watch the use of this SA, so a renegotiation can
+ * happen as soon as it is shown to be alive.
+ */
+ sa->flags |= SA_FLAG_FADING;
+}
+
+/* SA has passed its best before date. */
+static void
+sa_hard_expire(void *v_sa)
+{
+ struct sa *sa = v_sa;
+
+ sa->death = 0;
+ sa_release(sa);
+
+ if ((sa->flags & (SA_FLAG_STAYALIVE | SA_FLAG_REPLACED)) ==
+ SA_FLAG_STAYALIVE)
+ exchange_establish(sa->name, 0, 0);
+
+ sa_delete(sa, 1);
+}
+
+void
+sa_reinit(void)
+{
+ struct sa *sa;
+ char *tag;
+ int i;
+
+ /* For now; only do this if we have the proper tag configured. */
+ tag = conf_get_str("General", "Renegotiate-on-HUP");
+ if (!tag)
+ return;
+
+ LOG_DBG((LOG_SA, 30, "sa_reinit: renegotiating active connections"));
+
+ /*
+ * Get phase 2 SAs. Soft expire those without active exchanges. Do
+ * not touch a phase 2 SA where the soft expiration is not set, ie.
+ * the SA is not yet established.
+ */
+ for (i = 0; i <= bucket_mask; i++)
+ for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link))
+ if (sa->phase == 2)
+ if (exchange_lookup_by_name(sa->name,
+ sa->phase) == 0 && sa->soft_death) {
+ timer_remove_event(sa->soft_death);
+ sa_soft_expire(sa);
+ }
+}
+
+/*
+ * Get an SA attribute's flag value out of textual description.
+ */
+int
+sa_flag(char *attr)
+{
+ static struct sa_flag_map {
+ char *name;
+ int flag;
+ } sa_flag_map[] = {
+ {
+ "active-only", SA_FLAG_ACTIVE_ONLY
+ },
+
+ /*
+ * Below this point are flags that are internal to the
+ * implementation.
+ */
+ {
+ "__ondemand", SA_FLAG_ONDEMAND
+ },
+ {
+ "ikecfg", SA_FLAG_IKECFG
+ },
+ };
+ size_t i;
+
+ for (i = 0; i < sizeof sa_flag_map / sizeof sa_flag_map[0]; i++)
+ if (strcasecmp(attr, sa_flag_map[i].name) == 0)
+ return sa_flag_map[i].flag;
+ log_print("sa_flag: attribute \"%s\" unknown", attr);
+ return 0;
+}
+
+/* Mark SA as replaced. */
+void
+sa_mark_replaced(struct sa *sa)
+{
+ LOG_DBG((LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced",
+ sa, sa->name ? sa->name : "unnamed"));
+ sa->flags |= SA_FLAG_REPLACED;
+}
+
+/*
+ * Setup expiration timers for SA. This is used for ISAKMP SAs, but also
+ * possible to use for application SAs if the application does not deal
+ * with expirations itself. An example is the Linux FreeS/WAN KLIPS IPsec
+ * stack.
+ */
+int
+sa_setup_expirations(struct sa *sa)
+{
+ struct timeval expiration;
+ u_int64_t seconds = sa->seconds;
+
+ /*
+ * Set the soft timeout to a random percentage between 85 & 95 of
+ * the negotiated lifetime to break strictly synchronized
+ * renegotiations. This works better when the randomization is on the
+ * order of processing plus network-roundtrip times, or larger.
+ * I.e. it depends on configuration and negotiated lifetimes.
+ * It is not good to do the decrease on the hard timeout, because then
+ * we may drop our SA before our peer.
+ * XXX Better scheme to come?
+ */
+ if (!sa->soft_death) {
+ gettimeofday(&expiration, 0);
+ /*
+ * XXX This should probably be configuration controlled
+ * somehow.
+ */
+ seconds = sa->seconds * (850 + sysdep_random() % 100) / 1000;
+ LOG_DBG((LOG_TIMER, 95,
+ "sa_setup_expirations: SA %p soft timeout in %llu seconds",
+ sa, seconds));
+ expiration.tv_sec += seconds;
+ sa->soft_death = timer_add_event("sa_soft_expire",
+ sa_soft_expire, sa, &expiration);
+ if (!sa->soft_death) {
+ /* If we don't give up we might start leaking... */
+ sa_delete(sa, 1);
+ return -1;
+ }
+ sa_reference(sa);
+ }
+ if (!sa->death) {
+ gettimeofday(&expiration, 0);
+ LOG_DBG((LOG_TIMER, 95,
+ "sa_setup_expirations: SA %p hard timeout in %llu seconds",
+ sa, sa->seconds));
+ expiration.tv_sec += sa->seconds;
+ sa->death = timer_add_event("sa_hard_expire", sa_hard_expire,
+ sa, &expiration);
+ if (!sa->death) {
+ /* If we don't give up we might start leaking... */
+ sa_delete(sa, 1);
+ return -1;
+ }
+ sa_reference(sa);
+ }
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/sa.h b/keyexchange/isakmpd-20041012/sa.h
new file mode 100644
index 0000000..4f6100f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sa.h
@@ -0,0 +1,318 @@
+/* $OpenBSD: sa.h,v 1.41 2004/08/10 15:59:10 ho Exp $ */
+/* $EOM: sa.h,v 1.58 2000/10/10 12:39:01 provos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _SA_H_
+#define _SA_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include "isakmp.h"
+
+/* Remove a SA if it has not been fully negotiated in this time. */
+#define SA_NEGOTIATION_MAX_TIME 120
+
+struct crypto_xf;
+struct doi;
+struct event;
+struct exchange;
+struct keystate;
+struct message;
+struct payload;
+struct proto_attr;
+struct sa;
+struct transport;
+
+/* A protection suite consists of a set of protocol descriptions like this. */
+struct proto {
+ /* Link to the next protocol in the suite. */
+ TAILQ_ENTRY(proto) link;
+
+ /* The SA we belong to. */
+ struct sa *sa;
+
+ /* The protocol number as found in the proposal payload. */
+ u_int8_t no;
+
+ /* The protocol this SA is for. */
+ u_int8_t proto;
+
+ /*
+ * Security parameter index info. Element 0 - outgoing, 1 -
+ * incoming.
+ */
+ u_int8_t spi_sz[2];
+ u_int8_t *spi[2];
+
+ /*
+ * The chosen transform, only valid while the incoming SA payload that
+ * held it is available for duplicate testing.
+ */
+ struct payload *chosen;
+
+ /* The chosen transform's ID. */
+ u_int8_t id;
+
+ /* DOI-specific data. */
+ void *data;
+
+ /* Proposal transforms data, for validating the responders selection. */
+ TAILQ_HEAD(proto_attr_head, proto_attr) xfs;
+ size_t xf_cnt;
+};
+
+struct proto_attr {
+ /* Link to next transform. */
+ TAILQ_ENTRY(proto_attr) next;
+
+ /* Transform attribute data and size, suitable for attribute_map(). */
+ u_int8_t *attrs;
+ size_t len;
+};
+
+struct sa {
+ /* Link to SAs with the same hash value. */
+ LIST_ENTRY(sa) link;
+
+ /*
+ * When several SA's are being negotiated in one message we connect
+ * them through this link.
+ */
+ TAILQ_ENTRY(sa) next;
+
+ /*
+ * A name of the major policy deciding offers and acceptable
+ * proposals.
+ */
+ char *name;
+
+ /* The transport this SA got negotiated over. */
+ struct transport *transport;
+
+ /* Both initiator and responder cookies. */
+ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN];
+
+ /* The message ID signifying non-ISAKMP SAs. */
+ u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN];
+
+ /* The protection suite chosen. */
+ TAILQ_HEAD(proto_head, proto) protos;
+
+ /* The exchange type we should use when rekeying. */
+ u_int8_t exch_type;
+
+ /* Phase is 1 for ISAKMP SAs, and 2 for application ones. */
+ u_int8_t phase;
+
+ /* A reference counter for this structure. */
+ u_int16_t refcnt;
+
+ /* Various flags, look below for descriptions. */
+ u_int32_t flags;
+
+ /* The DOI that is to handle DOI-specific issues for this SA. */
+ struct doi *doi;
+
+ /*
+ * Crypto info needed to encrypt/decrypt packets protected by this
+ * SA.
+ */
+ struct crypto_xf *crypto;
+ int key_length;
+ struct keystate *keystate;
+
+ /* IDs from Phase 1 */
+ u_int8_t *id_i;
+ size_t id_i_len;
+ u_int8_t *id_r;
+ size_t id_r_len;
+
+ /* Set if we were the initiator of the SA/exchange in Phase 1 */
+ int initiator;
+
+ /* Policy session ID, where applicable, copied over from the exchange */
+ int policy_id;
+
+ /*
+ * The key used to authenticate phase 1, in printable format, used
+ * only by KeyNote.
+ */
+ char *keynote_key;
+
+ /*
+ * Certificates or other information from Phase 1; these are copied
+ * from the exchange, so look at exchange.h for an explanation of
+ * their use.
+ */
+ int recv_certtype, recv_keytype;
+ /* Certificate received from peer, native format. */
+ void *recv_cert;
+ /* Key peer used to authenticate, native format. */
+ void *recv_key;
+
+ /*
+ * Certificates or other information we used to authenticate to the
+ * peer, Phase 1.
+ */
+ int sent_certtype;
+ /* Certificate (to be) sent to peer, native format. */
+ void *sent_cert;
+
+ /* DOI-specific opaque data. */
+ void *data;
+
+ /* Lifetime data. */
+ u_int64_t seconds;
+ u_int64_t kilobytes;
+
+ /* ACQUIRE sequence number */
+ u_int32_t seq;
+
+ /* The events that will occur when an SA has timed out. */
+ struct event *soft_death;
+ struct event *death;
+
+#if defined (USE_NAT_TRAVERSAL)
+ struct event *nat_t_keepalive;
+#endif
+
+#if defined (USE_DPD)
+ /* IKE DPD (RFC3706) message sequence number. */
+ u_int32_t dpd_seq; /* sent */
+ u_int32_t dpd_rseq; /* recieved */
+ u_int32_t dpd_failcount; /* # of subsequent failures */
+ struct event *dpd_event; /* time of next event */
+#endif
+};
+
+/* This SA is alive. */
+#define SA_FLAG_READY 0x01
+
+/* Renegotiate the SA at each expiry. */
+#define SA_FLAG_STAYALIVE 0x02
+
+/* Establish the SA when it is needed. */
+#define SA_FLAG_ONDEMAND 0x04
+
+/* This SA has been replaced by another newer one. */
+#define SA_FLAG_REPLACED 0x08
+
+/* This SA has seen a soft timeout and wants to be renegotiated on use. */
+#define SA_FLAG_FADING 0x10
+
+/* This SA should always be actively renegotiated (with us as initiator). */
+#define SA_FLAG_ACTIVE_ONLY 0x20
+
+/* This SA flag is a placeholder for a TRANSACTION exchange "SA flag". */
+#define SA_FLAG_IKECFG 0x40
+
+/* This SA flag indicates if we should do DPD with the phase 1 SA peer. */
+#define SA_FLAG_DPD 0x80
+
+/* NAT-T encapsulation state. Kept in isakmp_sa for the new p2 exchange. */
+#define SA_FLAG_NAT_T_ENABLE 0x100
+#define SA_FLAG_NAT_T_KEEPALIVE 0x200
+
+extern void proto_free(struct proto * proto);
+extern int sa_add_transform(struct sa *, struct payload *, int,
+ struct proto **);
+extern int sa_create(struct exchange *, struct transport *);
+extern int sa_enter(struct sa *);
+extern void sa_delete(struct sa *, int);
+extern void sa_teardown_all(void);
+extern struct sa *sa_find(int (*) (struct sa *, void *), void *);
+extern int sa_flag(char *);
+extern void sa_free(struct sa *);
+extern void sa_init(void);
+extern void sa_reinit(void);
+extern struct sa *sa_isakmp_lookup_by_peer(struct sockaddr *, socklen_t);
+extern void sa_isakmp_upgrade(struct message *);
+extern struct sa *sa_lookup(u_int8_t *, u_int8_t *);
+extern struct sa *sa_lookup_by_peer(struct sockaddr *, socklen_t);
+extern struct sa *sa_lookup_by_header(u_int8_t *, int);
+extern struct sa *sa_lookup_by_name(char *, int);
+extern struct sa *sa_lookup_from_icookie(u_int8_t *);
+extern struct sa *sa_lookup_isakmp_sa(struct sockaddr *, u_int8_t *);
+extern void sa_mark_replaced(struct sa *);
+extern void sa_reference(struct sa *);
+extern void sa_release(struct sa *);
+extern void sa_remove(struct sa *);
+extern void sa_report(void);
+extern void sa_dump(int, int, char *, struct sa *);
+extern void sa_report_all(FILE *);
+extern int sa_setup_expirations(struct sa *);
+
+/*
+ * This structure contains most of the data of the in-kernel SA.
+ * Currently only used to collect the tdb_last_used time for DPD.
+ */
+struct sa_kinfo {
+ u_int32_t flags; /* /usr/include/netinet/ip_ipsp.h */
+
+ u_int32_t exp_allocations;
+ u_int32_t soft_allocations;
+ u_int32_t cur_allocations;
+
+ u_int64_t exp_bytes;
+ u_int64_t soft_bytes;
+ u_int64_t cur_bytes;
+
+ u_int64_t exp_timeout;
+ u_int64_t soft_timeout;
+
+ u_int64_t first_use;
+ u_int64_t established;
+ u_int64_t soft_first_use;
+ u_int64_t exp_first_use;
+
+ u_int64_t last_used;
+ u_int64_t last_marked;
+
+ struct sockaddr_storage dst;
+ struct sockaddr_storage src;
+ struct sockaddr_storage proxy;
+
+ u_int32_t spi;
+ u_int32_t rpl;
+ u_int16_t udpencap_port;
+ u_int16_t amxkeylen;
+ u_int16_t emxkeylen;
+ u_int16_t ivlen;
+ u_int8_t sproto;
+ u_int8_t wnd;
+ u_int8_t satype;
+};
+
+#endif /* _SA_H_ */
diff --git a/keyexchange/isakmpd-20041012/samples/Makefile b/keyexchange/isakmpd-20041012/samples/Makefile
new file mode 100644
index 0000000..558bd23
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/Makefile
@@ -0,0 +1,34 @@
+# $OpenBSD: Makefile,v 1.2 2003/06/03 14:39:50 ho Exp $
+# $EOM: Makefile,v 1.1 2000/05/01 20:04:53 niklas Exp $
+
+#
+# Copyright (c) 2000 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+FILES= VPN-* policy singlehost-*
+TARGETDIR= /usr/share/ipsec/isakmpd
+
+# The mkdir below is for installation on OpenBSD pre 2.7
+install:
+ @-mkdir -p ${DESTDIR}${TARGETDIR}
+ $(INSTALL) -c -m 0444 ${FILES} ${DESTDIR}${TARGETDIR}
diff --git a/keyexchange/isakmpd-20041012/samples/VPN-3way-template.conf b/keyexchange/isakmpd-20041012/samples/VPN-3way-template.conf
new file mode 100644
index 0000000..b64c801
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/VPN-3way-template.conf
@@ -0,0 +1,116 @@
+# $OpenBSD: VPN-3way-template.conf,v 1.11 2004/02/11 08:55:22 jmc Exp $
+# $EOM: VPN-3way-template.conf,v 1.8 2000/10/09 22:08:30 angelos Exp $
+#
+# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon.
+#
+# This is a template file of a VPN setup between three nodes in
+# a fully meshed 'three-way' configuration. Suggested use is to copy
+# this file to all three nodes and then edit them accordingly.
+#
+# These nodes are initially called XXX, YYY and ZZZ.
+#
+# In pseudographics: XXX --- YYY
+# \ /
+# ZZZ
+#
+# In cases where IP/network addresses should be defined values like
+# 192.168.XXX.nnn have been used.
+#
+
+# Incoming phase 1 negotiations are multiplexed on the source IP
+# address. In the three-way VPN, we have two possible peers.
+
+[Phase 1]
+192.168.YYY.nnn= ISAKMP-peer-node-YYY
+192.168.ZZZ.nnn= ISAKMP-peer-node-ZZZ
+
+# These connections are walked over after config file parsing and
+# told to the application layer so that it will inform us when
+# traffic wants to pass over them. This means we can do on-demand
+# keying. In the three-way VPN, each node knows two connections.
+
+[Phase 2]
+Connections= IPsec-Conn-XXX-YYY,IPsec-Conn-XXX-ZZZ
+
+# ISAKMP Phase 1 peer sections
+##############################
+
+[ISAKMP-peer-node-YYY]
+Phase= 1
+Transport= udp
+Address= 192.168.YYY.nnn
+Configuration= Default-main-mode
+Authentication= yoursharedsecretwithYYY
+
+[ISAKMP-peer-node-ZZZ]
+Phase= 1
+Transport= udp
+Address= 192.168.ZZZ.nnn
+Configuration= Default-main-mode
+Authentication= yoursharedsecretwithZZZ
+
+# IPsec Phase 2 sections
+########################
+
+[IPsec-Conn-XXX-YYY]
+Phase= 2
+ISAKMP-peer= ISAKMP-peer-node-YYY
+Configuration= Default-quick-mode
+Local-ID= MyNet-XXX
+Remote-ID= OtherNet-YYY
+
+[IPsec-Conn-XXX-ZZZ]
+Phase= 2
+ISAKMP-peer= ISAKMP-peer-node-ZZZ
+Configuration= Default-quick-mode
+Local-ID= MyNet-XXX
+Remote-ID= OtherNet-ZZZ
+
+# Client ID sections
+####################
+
+[MyNet-XXX]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.XXX.0
+Netmask= 255.255.255.0
+
+[OtherNet-YYY]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.YYY.0
+Netmask= 255.255.255.0
+
+[OtherNet-ZZZ]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.ZZZ.0
+Netmask= 255.255.255.0
+
+#
+# There is no more node-specific configuration below this point.
+#
+
+# Main mode descriptions
+
+[Default-main-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= ID_PROT
+Transforms= 3DES-SHA,3DES-MD5
+
+[Blowfish-main-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= ID_PROT
+Transforms= BLF-SHA-M1024
+
+# Quick mode description
+########################
+
+[Default-quick-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= QUICK_MODE
+Suites= QM-ESP-AES-SHA-PFS-SUITE
+
+[Blowfish-quick-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= QUICK_MODE
+Suites= QM-ESP-BLF-SHA-PFS-SUITE
+#Suites= QM-ESP-BLF-SHA-SUITE
+
diff --git a/keyexchange/isakmpd-20041012/samples/VPN-east.conf b/keyexchange/isakmpd-20041012/samples/VPN-east.conf
new file mode 100644
index 0000000..04d0bb9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/VPN-east.conf
@@ -0,0 +1,50 @@
+# $OpenBSD: VPN-east.conf,v 1.13 2003/03/16 08:13:02 matthieu Exp $
+# $EOM: VPN-east.conf,v 1.12 2000/10/09 22:08:30 angelos Exp $
+
+# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon.
+#
+# The network topology of the example net is like this:
+#
+# 192.168.11.0/24 - west [.11] - 10.1.0.0/24 - [.12] east - 192.168.12.0/24
+#
+# "west" and "east" are the respective security gateways (aka VPN-nodes).
+
+[Phase 1]
+10.1.0.11= ISAKMP-peer-west
+
+[Phase 2]
+Connections= IPsec-east-west
+
+[ISAKMP-peer-west]
+Phase= 1
+Transport= udp
+Address= 10.1.0.11
+Configuration= Default-main-mode
+Authentication= mekmitasdigoat
+
+[IPsec-east-west]
+Phase= 2
+ISAKMP-peer= ISAKMP-peer-west
+Configuration= Default-quick-mode
+Local-ID= Net-east
+Remote-ID= Net-west
+
+[Net-west]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.11.0
+Netmask= 255.255.255.0
+
+[Net-east]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.12.0
+Netmask= 255.255.255.0
+
+[Default-main-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= ID_PROT
+Transforms= 3DES-SHA
+
+[Default-quick-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= QUICK_MODE
+Suites= QM-ESP-AES-SHA-PFS-SUITE
diff --git a/keyexchange/isakmpd-20041012/samples/VPN-west.conf b/keyexchange/isakmpd-20041012/samples/VPN-west.conf
new file mode 100644
index 0000000..5b3a8f6
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/VPN-west.conf
@@ -0,0 +1,50 @@
+# $OpenBSD: VPN-west.conf,v 1.14 2003/03/16 08:13:02 matthieu Exp $
+# $EOM: VPN-west.conf,v 1.13 2000/10/09 22:08:30 angelos Exp $
+
+# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon.
+#
+# The network topology of the example net is like this:
+#
+# 192.168.11.0/24 - west [.11] - 10.1.0.0/24 - [.12] east - 192.168.12.0/24
+#
+# "west" and "east" are the respective security gateways (aka VPN-nodes).
+
+[Phase 1]
+10.1.0.12= ISAKMP-peer-east
+
+[Phase 2]
+Connections= IPsec-west-east
+
+[ISAKMP-peer-east]
+Phase= 1
+Transport= udp
+Address= 10.1.0.12
+Configuration= Default-main-mode
+Authentication= mekmitasdigoat
+
+[IPsec-west-east]
+Phase= 2
+ISAKMP-peer= ISAKMP-peer-east
+Configuration= Default-quick-mode
+Local-ID= Net-west
+Remote-ID= Net-east
+
+[Net-west]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.11.0
+Netmask= 255.255.255.0
+
+[Net-east]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.12.0
+Netmask= 255.255.255.0
+
+[Default-main-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= ID_PROT
+Transforms= 3DES-SHA
+
+[Default-quick-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= QUICK_MODE
+Suites= QM-ESP-AES-SHA-PFS-SUITE
diff --git a/keyexchange/isakmpd-20041012/samples/policy b/keyexchange/isakmpd-20041012/samples/policy
new file mode 100644
index 0000000..0e194aa
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/policy
@@ -0,0 +1,10 @@
+KeyNote-Version: 2
+Comment: This policy accepts ESP SAs from a remote that uses the right password
+ $OpenBSD: policy,v 1.6 2001/06/20 16:36:19 angelos Exp $
+ $EOM: policy,v 1.6 2000/10/09 22:08:30 angelos Exp $
+Authorizer: "POLICY"
+Licensees: "passphrase:mekmitasdigoat"
+Conditions: app_domain == "IPsec policy" &&
+ esp_present == "yes" &&
+ esp_enc_alg == "aes" &&
+ esp_auth_alg == "hmac-sha" -> "true";
diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-east.conf b/keyexchange/isakmpd-20041012/samples/singlehost-east.conf
new file mode 100644
index 0000000..f0afc46
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/singlehost-east.conf
@@ -0,0 +1,64 @@
+# $OpenBSD: singlehost-east.conf,v 1.10 2000/11/23 12:56:25 niklas Exp $
+# $EOM: singlehost-east.conf,v 1.10 2000/11/23 12:24:43 niklas Exp $
+
+# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon.
+
+[General]
+Listen-on= 10.1.0.12
+Shared-SADB= Defined
+Policy-File= policy
+
+[Phase 1]
+10.1.0.11= ISAKMP-peer-west
+Default= ISAKMP-peer-west-aggressive
+
+[Phase 2]
+Connections= IPsec-east-west
+
+[ISAKMP-peer-west]
+Phase= 1
+Transport= udp
+Local-address= 10.1.0.12
+Address= 10.1.0.11
+Configuration= Default-main-mode
+Authentication= mekmitasdigoat
+
+[ISAKMP-peer-west-aggressive]
+Phase= 1
+Transport= udp
+Local-address= 10.1.0.12
+Address= 10.1.0.11
+Configuration= Default-aggressive-mode
+Authentication= mekmitasdigoat
+
+[IPsec-east-west]
+Phase= 2
+ISAKMP-peer= ISAKMP-peer-west
+Configuration= Default-quick-mode
+Local-ID= Net-east
+Remote-ID= Net-west
+
+[Net-west]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.11.0
+Netmask= 255.255.255.0
+
+[Net-east]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.12.0
+Netmask= 255.255.255.0
+
+[Default-main-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= ID_PROT
+Transforms= 3DES-SHA
+
+[Default-aggressive-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= AGGRESSIVE
+Transforms= 3DES-SHA-RSA
+
+[Default-quick-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= QUICK_MODE
+Suites= QM-ESP-AES-SHA-PFS-SUITE
diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-east.gdb b/keyexchange/isakmpd-20041012/samples/singlehost-east.gdb
new file mode 100644
index 0000000..a41df0d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/singlehost-east.gdb
@@ -0,0 +1 @@
+r -d -D0=99 -D1=99 -D2=99 -D3=99 -D4=99 -D5=99 -feast.fifo -c../samples/singlehost-east.conf
diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-setup.sh b/keyexchange/isakmpd-20041012/samples/singlehost-setup.sh
new file mode 100644
index 0000000..818ce2d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/singlehost-setup.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# $OpenBSD: singlehost-setup.sh,v 1.5 2003/08/18 09:41:40 markus Exp $
+# $EOM: singlehost-setup.sh,v 1.3 2000/11/23 12:24:43 niklas Exp $
+
+# A script to test single-host VPNs
+
+# For the 'pf' variable
+. /etc/rc.conf
+
+# Default paths
+PFCTL=/sbin/pfctl
+ISAKMPD=/sbin/isakmpd
+
+do_routes()
+{
+ /sbin/route $1 -net 192.168.11.0/24 192.168.11.1 -iface >/dev/null
+ /sbin/route $1 -net 192.168.12.0/24 192.168.12.1 -iface >/dev/null
+ /sbin/route $1 -net 10.1.0.0/16 10.1.0.11 -iface >/dev/null
+}
+
+# Called on script exit
+cleanup () {
+ if [ "x${pf}" = "xYES" -a -f ${pf_rules} ]; then
+ ${PFCTL} -R -f ${pf_rules}
+ else
+ ${PFCTL} -qd
+ fi
+
+ USER=`id -p | grep ^login | cut -f2`
+ chown $USER singlehost-east.conf singlehost-west.conf policy
+ chmod 644 singlehost-east.conf singlehost-west.conf policy
+
+ [ -p east.fifo ] && echo "Q" >> east.fifo
+ [ -p west.fifo ] && echo "Q" >> west.fifo
+ rm -f east.fifo west.fifo
+
+ do_routes delete
+}
+
+# Start by initializing interfaces
+/sbin/ifconfig lo2 192.168.11.1 netmask 0xffffff00 up
+/sbin/ifconfig lo3 192.168.12.1 netmask 0xffffff00 up
+/sbin/ifconfig lo4 10.1.0.11 netmask 0xffff0000 up
+/sbin/ifconfig lo5 10.1.0.12 netmask 0xffff0000 up
+# ... and by adding the required routes
+do_routes add
+
+# Add rules
+(
+ cat <<EOF
+pass out quick on lo2 proto 50 all
+pass out quick on lo2 from 192.168.11.0/24 to any
+pass out quick on lo3 proto 50 all
+pass out quick on lo3 from 192.168.12.0/24 to any
+block out on lo2 all
+block out on lo3 all
+EOF
+ if [ "x${pf}" = "xYES" -a -f ${pf_rules} ]; then
+ cat ${pf_rules} | egrep -v '^(scrub|rdr|binat|nat)'
+ else
+ pfctl -qe >/dev/null
+ fi
+) | pfctl -R -f -
+
+trap cleanup 1 2 3 15
+
+# The configuration files needs proper owners and modes
+USER=`id -p | grep ^uid | cut -f2`
+chown $USER singlehost-east.conf singlehost-west.conf policy
+chmod 600 singlehost-east.conf singlehost-west.conf policy
+
+# Start the daemons
+rm -f east.fifo west.fifo
+${ISAKMPD} -c singlehost-east.conf -f east.fifo "$@"
+${ISAKMPD} -c singlehost-west.conf -f west.fifo "$@"
+
+# Give them some time to negotiate their stuff...
+SECS=3
+echo "Waiting $SECS seconds..."
+sleep $SECS
+echo "Running 'ping', using the tunnel..."
+ping -I 192.168.11.1 -c 5 192.168.12.1
+
+cleanup
diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-west.conf b/keyexchange/isakmpd-20041012/samples/singlehost-west.conf
new file mode 100644
index 0000000..40538a3
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/singlehost-west.conf
@@ -0,0 +1,64 @@
+# $OpenBSD: singlehost-west.conf,v 1.11 2003/08/20 14:43:36 ho Exp $
+# $EOM: singlehost-west.conf,v 1.10 2000/11/23 12:24:43 niklas Exp $
+
+# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon.
+
+[General]
+Listen-on= 10.1.0.11
+Shared-SADB= Defined
+Policy-File= policy
+
+[Phase 1]
+10.1.0.12= ISAKMP-peer-east
+Default= ISAKMP-peer-east-aggressive
+
+[Phase 2]
+Connections= IPsec-west-east
+
+[ISAKMP-peer-east]
+Phase= 1
+Transport= udp
+Local-address= 10.1.0.11
+Address= 10.1.0.12
+Configuration= Default-main-mode
+Authentication= mekmitasdigoat
+
+[ISAKMP-peer-east-aggressive]
+Phase= 1
+Transport= udp
+Local-address= 10.1.0.11
+Address= 10.1.0.12
+Configuration= Default-aggressive-mode
+Authentication= mekmitasdigoat
+
+[IPsec-west-east]
+Phase= 2
+ISAKMP-peer= ISAKMP-peer-east
+Configuration= Default-quick-mode
+Local-ID= Net-west
+Remote-ID= Net-east
+
+[Net-west]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.11.0
+Netmask= 255.255.255.0
+
+[Net-east]
+ID-type= IPV4_ADDR_SUBNET
+Network= 192.168.12.0
+Netmask= 255.255.255.0
+
+[Default-main-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= ID_PROT
+Transforms= 3DES-SHA
+
+[Default-aggressive-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= AGGRESSIVE
+Transforms= 3DES-SHA-RSA
+
+[Default-quick-mode]
+DOI= IPSEC
+EXCHANGE_TYPE= QUICK_MODE
+Suites= QM-ESP-AES-SHA-PFS-SUITE
diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-west.gdb b/keyexchange/isakmpd-20041012/samples/singlehost-west.gdb
new file mode 100644
index 0000000..5315e46
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/samples/singlehost-west.gdb
@@ -0,0 +1 @@
+r -d -D0=99 -D1=99 -D2=99 -D3=99 -D4=99 -D5=99 -fwest.fifo -c../samples/singlehost-west.conf
diff --git a/keyexchange/isakmpd-20041012/sysdep.h b/keyexchange/isakmpd-20041012/sysdep.h
new file mode 100644
index 0000000..50de819
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep.h
@@ -0,0 +1,84 @@
+/* $OpenBSD: sysdep.h,v 1.19 2004/08/10 15:59:10 ho Exp $ */
+/* $EOM: sysdep.h,v 1.17 2000/12/04 04:46:35 angelos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _SYSDEP_H_
+#define _SYSDEP_H_
+
+#include <sys/types.h>
+#if defined (USE_BOEHM_GC)
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include "sysdep-os.h"
+
+struct proto;
+struct sa;
+struct sockaddr;
+
+extern void sysdep_app_handler(int);
+extern int sysdep_app_open(void);
+extern int sysdep_cleartext(int, int);
+extern void sysdep_connection_check(char *);
+extern int sysdep_ipsec_delete_spi(struct sa *, struct proto *, int);
+extern int sysdep_ipsec_enable_sa(struct sa *, struct sa *);
+extern u_int8_t *sysdep_ipsec_get_spi(size_t *, u_int8_t, struct sockaddr *,
+ struct sockaddr *, u_int32_t);
+extern struct sa_kinfo *sysdep_ipsec_get_kernel_sa(u_int8_t *, size_t,
+ u_int8_t, struct sockaddr *);
+extern int sysdep_ipsec_group_spis(struct sa *, struct proto *,
+ struct proto *, int);
+extern int sysdep_ipsec_set_spi(struct sa *, struct proto *, int,
+ struct sa *);
+extern char *sysdep_progname(void);
+extern u_int32_t sysdep_random(void);
+extern u_int8_t sysdep_sa_len(struct sockaddr *);
+
+#if defined (USE_BOEHM_GC)
+/*
+ * Use Boehm's garbage collector as a means to find leaks.
+ * XXX The defines below are GCC-specific. I think it is OK to require
+ * XXX GCC if you are debugging isakmpd in this way.
+ */
+void *GC_debug_malloc(size_t, char *, int);
+void *GC_debug_realloc(void *, size_t, char *, int);
+void GC_debug_free(void *);
+char *gc_strdup(const char *);
+
+#define malloc(x) GC_debug_malloc ((x), __FILE__, __LINE__)
+#define realloc(x,y) GC_debug_realloc ((x), (y), __FILE__, __LINE__)
+#define free(x) GC_debug_free (x)
+#define calloc(x,y) malloc((x) * (y))
+#define strdup(x) gc_strdup((x))
+
+#endif /* WITH_BOEHM_GC */
+
+#endif /* _SYSDEP_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/bsdi/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/bsdi/GNUmakefile.sysdep
new file mode 100644
index 0000000..cc7b8cc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/bsdi/GNUmakefile.sysdep
@@ -0,0 +1,64 @@
+# $OpenBSD: GNUmakefile.sysdep,v 1.3 2003/06/03 14:53:11 ho Exp $
+#
+# XXX UNTESTED
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
+# Copyright (c) 2000 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+LIBGMP:=
+LIBCRYPTO:= /usr/contrib/lib/libcrypto.a
+
+LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep
+LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a
+
+LDADD+= ${LIBGMP} ${LIBSYSDEP}
+DPADD+= ${LIBGMP} ${LIBSYSDEP}
+
+FEATURES= debug tripledes blowfish cast ec aggressive
+# Not yet
+#FEATURES+= policy x509
+
+CFLAGS+= -DNO_RSA -DNO_RC5 -DNO_IDEA \
+ -I${.CURDIR}/sysdep/common -I/usr/contrib/include \
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
+
+#
+# hack libsysdep.a dependency
+#
+${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}:
+ @cd ${LIBSYSDEPDIR} && \
+ ${MAKE} --no-print-directory ${MAKEFLAGS} \
+ CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS}
+
+depend: ${LIBSYSDEPDIR}/.depend
+
+ifeq ($(findstring clean, $(MAKECMDGOALS)), clean)
+SUBDIR+= sysdep/common/libsysdep
+MAKEFLAGS+= --no-print-directory
+endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/bsdi/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/bsdi/Makefile.sysdep
new file mode 100644
index 0000000..3840fec
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/bsdi/Makefile.sysdep
@@ -0,0 +1,79 @@
+# $OpenBSD: Makefile.sysdep,v 1.6 2004/06/26 03:40:57 mcbride Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
+# Copyright (c) 2000 H\xe5kan Olsson. All rights reserved.
+# Copyright (c) 2001 Markus Friedl. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 INN 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.
+#
+
+# Override default features
+FEATURES= tripledes des blowfish cast ec aggressive debug x509
+FEATURES+= rawkey
+# Not yet
+#FEATURES+= policy isakmp_cfg
+
+LIBCRYPTO= /usr/contrib/lib/libcrypto.a
+LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep
+
+CFLAGS+= -DHAVE_PCAP
+
+LDADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a -lipsec
+DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a ${LIBIPSEC}
+
+SYSSRC=/usr/build/kame/bsdi4/sys
+
+.if exists(${SYSSRC}/net/pfkeyv2.h)
+CFLAGS+= -I${SYSSRC}
+.endif
+
+.if exists(/usr/build/keynote/keynote.h)
+CFLAGS+= -I/usr/build/keynote
+LDFLAGS+= -L/usr/build/keynote
+.endif
+
+CFLAGS+= -DNO_IDEA -DNO_RC5 -DHAVE_GETIFADDRS \
+ -I${.CURDIR}/sysdep/common
+CFLAGS+= -I/usr/include -I/usr/contrib/include
+
+LDADD+= -L/usr/contrib/lib
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
+USE_GMP= defined
+USE_KEYNOTE= defined
+
+# This is a hack in order to make sure libsysdep is built before the
+# linkstage of isakmpd. As a side effect the link is always done even if
+# not necessary. Well, I just don't care.
+GENERATED+= sysdep-target
+sysdep-target:
+ cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS}
+
+.if make(clean) || make(cleandir)
+SUBDIR+= sysdep/common/libsysdep
+.endif
+
+# Kludge around bug in /usr/share/mk/bsd.subdir.mk
+NO_REGRESS= defined
diff --git a/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep-os.h
new file mode 100644
index 0000000..710ab82
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep-os.h
@@ -0,0 +1,66 @@
+/* $OpenBSD: sysdep-os.h,v 1.5 2003/08/06 11:20:00 markus Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000 H\xe5kan Olsson. All rights reserved.
+ * Copyright (c) 2001 Markus Friedl. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _SYSDEP_OS_H_
+
+#define _SYSDEP_OS_H_
+
+#define KAME
+
+#include <netinet6/ipsec.h>
+
+/* in_port_t */
+#include <netinet/in.h>
+
+#define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+
+#ifndef CPI_RESERVED_MIN
+/* Reserved CPI numbers */
+#define CPI_RESERVED_MIN 1
+#define CPI_RESERVED_MAX 255
+#define CPI_PRIVATE_MIN 61440
+#define CPI_PRIVATE_MAX 65535
+#endif
+
+#if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC)
+#define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC
+#endif
+
+#if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC)
+#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC
+#endif
+
+#endif /* _SYSDEP_OS_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep.c
new file mode 100644
index 0000000..99715d5
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep.c
@@ -0,0 +1,225 @@
+/* $OpenBSD: sysdep.c,v 1.12 2004/08/10 15:59:10 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000 H\xe5kan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "util.h"
+
+#ifdef NEED_SYSDEP_APP
+#include "app.h"
+#include "conf.h"
+#include "ipsec.h"
+
+#ifdef USE_PF_KEY_V2
+#include "pf_key_v2.h"
+#define KEY_API(x) pf_key_v2_##x
+#endif
+
+#endif /* NEED_SYSDEP_APP */
+#include "log.h"
+
+extern char *__progname;
+
+/*
+ * An as strong as possible random number generator, reverting to a
+ * deterministic pseudo-random one if regrand is set.
+ */
+u_int32_t
+sysdep_random ()
+{
+ return random();
+}
+
+/* Return the basename of the command used to invoke us. */
+char *
+sysdep_progname ()
+{
+ return __progname;
+}
+
+/* Return the length of the sockaddr struct. */
+u_int8_t
+sysdep_sa_len (struct sockaddr *sa)
+{
+ return sa->sa_len;
+}
+
+/* As regress/ use this file I protect the sysdep_app_* stuff like this. */
+#ifdef NEED_SYSDEP_APP
+/*
+ * Prepare the application we negotiate SAs for (i.e. the IPsec stack)
+ * for communication. We return a file descriptor useable to select(2) on.
+ */
+int
+sysdep_app_open ()
+{
+ return KEY_API(open) ();
+}
+
+/*
+ * When select(2) has noticed our application needs attendance, this is what
+ * gets called. FD is the file descriptor causing the alarm.
+ */
+void
+sysdep_app_handler (int fd)
+{
+ KEY_API (handler) (fd);
+}
+
+/* Check that the connection named NAME is active, or else make it active. */
+void
+sysdep_connection_check (char *name)
+{
+ KEY_API (connection_check) (name);
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ if (app_none)
+ {
+ *sz = IPSEC_SPI_SIZE;
+ /* XXX should be random instead I think. */
+ return strdup ("\x12\x34\x56\x78");
+ }
+ return KEY_API (get_spi) (sz, proto, src, dst, seq);
+}
+
+struct sa_kinfo *
+sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
+ struct sockaddr *dst)
+{
+ if (app_none)
+ return 0;
+ /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */
+ return 0;
+}
+
+/* Force communication on socket FD to go in the clear. */
+int
+sysdep_cleartext (int fd, int af)
+{
+ char *buf;
+ char *policy[] = { "in bypass", "out bypass", NULL };
+ char **p;
+ int ipp;
+ int opt;
+ char *msgstr;
+
+ if (app_none)
+ return 0;
+
+ switch (af)
+ {
+ case AF_INET:
+ ipp = IPPROTO_IP;
+ opt = IP_IPSEC_POLICY;
+ msgstr = "";
+ break;
+ case AF_INET6:
+ ipp = IPPROTO_IPV6;
+ opt = IPV6_IPSEC_POLICY;
+ msgstr = "V6";
+ break;
+ default:
+ log_print ("sysdep_cleartext: unsupported protocol family %d", af);
+ return -1;
+ }
+
+ /*
+ * Need to bypass system security policy, so I can send and
+ * receive key management datagrams in the clear.
+ */
+
+ for (p = policy; p && *p; p++)
+ {
+ buf = ipsec_set_policy (*p, strlen(*p));
+ if (buf == NULL)
+ {
+ log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror());
+ return -1;
+ }
+
+ if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0)
+ {
+ log_error ("sysdep_cleartext: "
+ "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) "
+ "failed", fd, msgstr, msgstr);
+ return -1;
+ }
+ free(buf);
+ }
+
+ return 0;
+}
+
+int
+sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (delete_spi) (sa, proto, incoming);
+}
+
+int
+sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (enable_sa) (sa, isakmp_sa);
+}
+
+int
+sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (group_spis) (sa, proto1, proto2, incoming);
+}
+
+int
+sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/blf.h b/keyexchange/isakmpd-20041012/sysdep/common/blf.h
new file mode 100644
index 0000000..97eec89
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/blf.h
@@ -0,0 +1,70 @@
+/* $OpenBSD: blf.h,v 1.5 2003/06/03 14:52:06 ho Exp $ */
+/*
+ * Blowfish - a fast block cipher designed by Bruce Schneier
+ *
+ * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _BLF_H_
+#define _BLF_H_
+
+/* Schneier states the maximum key length to be 56 bytes.
+ * The way how the subkeys are initialized by the key up
+ * to (N+2)*4 i.e. 72 bytes are utilized.
+ * Warning: For normal blowfish encryption only 56 bytes
+ * of the key affect all cipherbits.
+ */
+
+#define BLF_N 16 /* Number of Subkeys */
+#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */
+
+/* Blowfish context */
+typedef struct BlowfishContext {
+ u_int32_t S[4][256]; /* S-Boxes */
+ u_int32_t P[BLF_N + 2]; /* Subkeys */
+} blf_ctx;
+
+/* Raw access to customized Blowfish
+ * blf_key is just:
+ * Blowfish_initstate( state )
+ * Blowfish_expand0state( state, key, keylen )
+ */
+
+void Blowfish_encipher(blf_ctx *, u_int32_t *, u_int32_t *);
+void Blowfish_decipher(blf_ctx *, u_int32_t *, u_int32_t *);
+void Blowfish_initstate(blf_ctx *);
+void Blowfish_expand0state(blf_ctx *, const u_int8_t *, u_int16_t);
+void Blowfish_expandstate
+(blf_ctx *, const u_int8_t *, u_int16_t, const u_int8_t *, u_int16_t);
+
+/* Standard Blowfish */
+
+void blf_key(blf_ctx *, const u_int8_t *, u_int16_t);
+void blf_enc(blf_ctx *, u_int32_t *, u_int16_t);
+void blf_dec(blf_ctx *, u_int32_t *, u_int16_t);
+
+/* Converts u_int8_t to u_int32_t */
+u_int32_t Blowfish_stream2word(const u_int8_t *, u_int16_t , u_int16_t *);
+
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/cast.h b/keyexchange/isakmpd-20041012/sysdep/common/cast.h
new file mode 100644
index 0000000..c130986
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/cast.h
@@ -0,0 +1,22 @@
+/* $OpenBSD: cast.h,v 1.1 2001/01/26 11:34:00 niklas Exp $ */
+/*
+ * CAST-128 in C
+ * Written by Steve Reid <sreid@sea-to-sky.net>
+ * 100% Public Domain - no warranty
+ * Released 1997.10.11
+ */
+
+#ifndef _CAST_H_
+#define _CAST_H_
+
+typedef struct {
+ u_int32_t xkey[32]; /* Key, after expansion */
+ int rounds; /* Number of rounds to use, 12 or 16 */
+} cast_key;
+
+void cast_setkey(cast_key* key, u_int8_t* rawkey, int keybytes);
+void cast_encrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock);
+void cast_decrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock);
+
+#endif /* ifndef _CAST_H_ */
+
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/GNUmakefile b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/GNUmakefile
new file mode 100644
index 0000000..3b62328
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/GNUmakefile
@@ -0,0 +1,57 @@
+# $OpenBSD: GNUmakefile,v 1.4 2003/06/03 14:52:06 ho Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+.CURDIR:= $(shell pwd)
+
+LIB= sysdep
+SRCS= arc4random.c blowfish.c cast.c md5.c sha1.c strlcat.c strlcpy.c
+NOMAN=
+CFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine
+
+lib${LIB}.a: ${SRCS:%.c=%.o}
+ ar cq $@ ${SRCS:%.c=%.o}
+
+clean:
+ rm -f lib${LIB}.a ${SRCS:%.c=%.o}
+
+cleandir: clean cleandepend
+
+depend: .depend
+
+.depend: ${SRCS}
+ @rm -f .depend
+ ${MKDEP} ${CFLAGS} ${SRCS} > .depend
+
+cleandepend:
+ rm -f .depend
+
+ifneq ($(findstring clean,$(MAKECMDGOALS)),clean)
+-include .depend
+endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/Makefile b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/Makefile
new file mode 100644
index 0000000..fce68d3
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/Makefile
@@ -0,0 +1,43 @@
+# $OpenBSD: Makefile,v 1.4 2003/06/03 14:52:06 ho Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+OPSYS!= uname -s
+
+LIB= sysdep
+SRCS= arc4random.c blowfish.c cast.c md5.c sha1.c strlcat.c strlcpy.c
+NOPROFILE=
+NOPIC=
+NOMAN=
+.if ${OPSYS} == "NetBSD"
+CPPFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine
+.else
+CFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine
+.endif
+
+.include <bsd.lib.mk>
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/arc4random.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/arc4random.c
new file mode 100644
index 0000000..afd5bb6
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/arc4random.c
@@ -0,0 +1,178 @@
+/* $OpenBSD: arc4random.c,v 1.6 2004/10/08 15:18:26 hshoexer Exp $ */
+
+/*
+ * Arc4 random number generator for OpenBSD.
+ * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
+ *
+ * Modification and redistribution in source and binary forms is
+ * permitted provided that due credit is given to the author and the
+ * OpenBSD project by leaving this copyright notice intact.
+ */
+
+/*
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret). The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * Here the stream cipher has been modified always to include the time
+ * when initializing the state. That makes it impossible to
+ * regenerate the same random sequence twice, so this can't be used
+ * for encryption, but will generate good random numbers.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef __GNUC__
+#define inline __inline
+#else /* !__GNUC__ */
+#define inline
+#endif /* !__GNUC__ */
+
+struct arc4_stream {
+ u_int8_t i;
+ u_int8_t j;
+ u_int8_t s[256];
+};
+
+int rs_initialized;
+static struct arc4_stream rs;
+
+static inline u_int8_t arc4_getbyte(struct arc4_stream *);
+
+static inline void
+arc4_init(struct arc4_stream *as)
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ as->s[n] = n;
+ as->i = 0;
+ as->j = 0;
+}
+
+static inline void
+arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
+{
+ int n;
+ u_int8_t si;
+
+ as->i--;
+ for (n = 0; n < 256; n++) {
+ as->i = (as->i + 1);
+ si = as->s[as->i];
+ as->j = (as->j + si + dat[n % datlen]);
+ as->s[as->i] = as->s[as->j];
+ as->s[as->j] = si;
+ }
+ as->j = as->i;
+}
+
+static void
+arc4_stir(struct arc4_stream *as)
+{
+ int fd, i;
+ struct {
+ struct timeval tv;
+ u_int8_t rnd[128 - sizeof(struct timeval)];
+ } rdat;
+
+ gettimeofday(&rdat.tv, NULL);
+ fd = open("/dev/arandom", O_RDONLY);
+ if (fd < 0)
+ fd = open("/dev/random", O_RDONLY);
+ if (fd >= 0) {
+ read(fd, rdat.rnd, sizeof(rdat.rnd));
+ close(fd);
+ }
+ /* fd < 0? Ah, what the heck. We'll just take whatever was on the
+ * stack... */
+
+ arc4_addrandom(as, (void *)&rdat, sizeof(rdat));
+
+ /*
+ * Discard early keystream, as per recommendations in:
+ * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+ */
+ for (i = 0; i < 256; i++)
+ (void)arc4_getbyte(as);
+}
+
+static inline u_int8_t
+arc4_getbyte(struct arc4_stream *as)
+{
+ u_int8_t si, sj;
+
+ as->i = (as->i + 1);
+ si = as->s[as->i];
+ as->j = (as->j + si);
+ sj = as->s[as->j];
+ as->s[as->i] = sj;
+ as->s[as->j] = si;
+ return (as->s[(si + sj) & 0xff]);
+}
+
+static inline u_int32_t
+arc4_getword(struct arc4_stream *as)
+{
+ u_int32_t val;
+ val = arc4_getbyte(as) << 24;
+ val |= arc4_getbyte(as) << 16;
+ val |= arc4_getbyte(as) << 8;
+ val |= arc4_getbyte(as);
+ return val;
+}
+
+void
+arc4random_stir(void)
+{
+ if (!rs_initialized) {
+ arc4_init(&rs);
+ rs_initialized = 1;
+ }
+ arc4_stir(&rs);
+}
+
+void
+arc4random_addrandom(u_char *dat, int datlen)
+{
+ if (!rs_initialized)
+ arc4random_stir();
+ arc4_addrandom(&rs, dat, datlen);
+}
+
+u_int32_t
+arc4random(void)
+{
+ if (!rs_initialized)
+ arc4random_stir();
+ return arc4_getword(&rs);
+}
+
+#if 0
+/*-------- Test code for i386 --------*/
+#include <stdio.h>
+#include <machine/pctr.h>
+int
+main(int argc, char **argv)
+{
+ const int iter = 1000000;
+ int i;
+ pctrval v;
+
+ v = rdtsc();
+ for (i = 0; i < iter; i++)
+ arc4random();
+ v = rdtsc() - v;
+ v /= iter;
+
+ printf("%qd cycles\n", v);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/blowfish.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/blowfish.c
new file mode 100644
index 0000000..5c59f4b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/blowfish.c
@@ -0,0 +1,685 @@
+/* $OpenBSD: blowfish.c,v 1.4 2003/06/03 14:52:06 ho Exp $ */
+/*
+ * Blowfish block cipher for OpenBSD
+ * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
+ * All rights reserved.
+ *
+ * Implementation advice by David Mazieres <dm@lcs.mit.edu>.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code is derived from section 14.3 and the given source
+ * in section V of Applied Cryptography, second edition.
+ * Blowfish is an unpatented fast block cipher designed by
+ * Bruce Schneier.
+ */
+
+#if 0
+#include <stdio.h> /* used for debugging */
+#include <string.h>
+#endif
+
+#include <sys/types.h>
+#include <blf.h>
+
+#undef inline
+#ifdef __GNUC__
+#define inline __inline
+#else /* !__GNUC__ */
+#define inline
+#endif /* !__GNUC__ */
+
+/* Function for Feistel Networks */
+
+#define F(bc, x) ((((bc)->S[0][((x) & 0xFF000000) >> 24] \
+ + (bc)->S[1][((x) &0xFF0000 ) >> 16]) \
+ ^ (bc)->S[2][((x) & 0xFF00) >> 8]) \
+ + (bc)->S[3][(x) & 0x00FF])
+
+#define BLFRND(bc,i,j,n) (i ^= F(bc,j) ^ (bc)->P[n])
+
+void
+Blowfish_encipher(c, xl, xr)
+ blf_ctx *c;
+ u_int32_t *xl;
+ u_int32_t *xr;
+{
+ u_int32_t Xl;
+ u_int32_t Xr;
+
+ Xl = *xl;
+ Xr = *xr;
+
+ Xl ^= c->P[0];
+ BLFRND(c, Xr, Xl, 1); BLFRND(c, Xl, Xr, 2);
+ BLFRND(c, Xr, Xl, 3); BLFRND(c, Xl, Xr, 4);
+ BLFRND(c, Xr, Xl, 5); BLFRND(c, Xl, Xr, 6);
+ BLFRND(c, Xr, Xl, 7); BLFRND(c, Xl, Xr, 8);
+ BLFRND(c, Xr, Xl, 9); BLFRND(c, Xl, Xr, 10);
+ BLFRND(c, Xr, Xl, 11); BLFRND(c, Xl, Xr, 12);
+ BLFRND(c, Xr, Xl, 13); BLFRND(c, Xl, Xr, 14);
+ BLFRND(c, Xr, Xl, 15); BLFRND(c, Xl, Xr, 16);
+
+ *xl = Xr ^ c->P[17];
+ *xr = Xl;
+}
+
+void
+Blowfish_decipher(c, xl, xr)
+ blf_ctx *c;
+ u_int32_t *xl;
+ u_int32_t *xr;
+{
+ u_int32_t Xl;
+ u_int32_t Xr;
+
+ Xl = *xl;
+ Xr = *xr;
+
+ Xl ^= c->P[17];
+ BLFRND(c, Xr, Xl, 16); BLFRND(c, Xl, Xr, 15);
+ BLFRND(c, Xr, Xl, 14); BLFRND(c, Xl, Xr, 13);
+ BLFRND(c, Xr, Xl, 12); BLFRND(c, Xl, Xr, 11);
+ BLFRND(c, Xr, Xl, 10); BLFRND(c, Xl, Xr, 9);
+ BLFRND(c, Xr, Xl, 8); BLFRND(c, Xl, Xr, 7);
+ BLFRND(c, Xr, Xl, 6); BLFRND(c, Xl, Xr, 5);
+ BLFRND(c, Xr, Xl, 4); BLFRND(c, Xl, Xr, 3);
+ BLFRND(c, Xr, Xl, 2); BLFRND(c, Xl, Xr, 1);
+
+ *xl = Xr ^ c->P[0];
+ *xr = Xl;
+}
+
+void
+Blowfish_initstate(c)
+ blf_ctx *c;
+{
+
+/* P-box and S-box tables initialized with digits of Pi */
+
+ const blf_ctx initstate =
+
+ { {
+ {
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a},
+ {
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7},
+ {
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0},
+ {
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6}
+ },
+ {
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+ 0x9216d5d9, 0x8979fb1b
+ } };
+
+ *c = initstate;
+
+}
+
+u_int32_t
+Blowfish_stream2word(const u_int8_t *data, u_int16_t databytes, u_int16_t *current)
+{
+ u_int8_t i;
+ u_int16_t j;
+ u_int32_t temp;
+
+ temp = 0x00000000;
+ j = *current;
+
+ for (i = 0; i < 4; i++, j++) {
+ if (j >= databytes)
+ j = 0;
+ temp = (temp << 8) | data[j];
+ }
+
+ *current = j;
+ return temp;
+}
+
+void
+Blowfish_expand0state(blf_ctx *c, const u_int8_t *key, u_int16_t keybytes)
+{
+ u_int16_t i;
+ u_int16_t j;
+ u_int16_t k;
+ u_int32_t temp;
+ u_int32_t datal;
+ u_int32_t datar;
+
+ j = 0;
+ for (i = 0; i < BLF_N + 2; i++) {
+ /* Extract 4 int8 to 1 int32 from keystream */
+ temp = Blowfish_stream2word(key, keybytes, &j);
+ c->P[i] = c->P[i] ^ temp;
+ }
+
+ j = 0;
+ datal = 0x00000000;
+ datar = 0x00000000;
+ for (i = 0; i < BLF_N + 2; i += 2) {
+ Blowfish_encipher(c, &datal, &datar);
+
+ c->P[i] = datal;
+ c->P[i + 1] = datar;
+ }
+
+ for (i = 0; i < 4; i++) {
+ for (k = 0; k < 256; k += 2) {
+ Blowfish_encipher(c, &datal, &datar);
+
+ c->S[i][k] = datal;
+ c->S[i][k + 1] = datar;
+ }
+ }
+}
+
+
+void
+Blowfish_expandstate(blf_ctx *c, const u_int8_t *data, u_int16_t databytes,
+ const u_int8_t *key, u_int16_t keybytes)
+{
+ u_int16_t i;
+ u_int16_t j;
+ u_int16_t k;
+ u_int32_t temp;
+ u_int32_t datal;
+ u_int32_t datar;
+
+ j = 0;
+ for (i = 0; i < BLF_N + 2; i++) {
+ /* Extract 4 int8 to 1 int32 from keystream */
+ temp = Blowfish_stream2word(key, keybytes, &j);
+ c->P[i] = c->P[i] ^ temp;
+ }
+
+ j = 0;
+ datal = 0x00000000;
+ datar = 0x00000000;
+ for (i = 0; i < BLF_N + 2; i += 2) {
+ datal ^= Blowfish_stream2word(data, databytes, &j);
+ datar ^= Blowfish_stream2word(data, databytes, &j);
+ Blowfish_encipher(c, &datal, &datar);
+
+ c->P[i] = datal;
+ c->P[i + 1] = datar;
+ }
+
+ for (i = 0; i < 4; i++) {
+ for (k = 0; k < 256; k += 2) {
+ datal ^= Blowfish_stream2word(data, databytes, &j);
+ datar ^= Blowfish_stream2word(data, databytes, &j);
+ Blowfish_encipher(c, &datal, &datar);
+
+ c->S[i][k] = datal;
+ c->S[i][k + 1] = datar;
+ }
+ }
+
+}
+
+void
+blf_key(blf_ctx *c, const u_int8_t *k, u_int16_t len)
+{
+ /* Initialize S-boxes and subkeys with Pi */
+ Blowfish_initstate(c);
+
+ /* Transform S-boxes and subkeys with key */
+ Blowfish_expand0state(c, k, len);
+}
+
+void
+blf_enc(blf_ctx *c, u_int32_t *data, u_int16_t blocks)
+{
+ u_int32_t *d;
+ u_int16_t i;
+
+ d = data;
+ for (i = 0; i < blocks; i++) {
+ Blowfish_encipher(c, d, d + 1);
+ d += 2;
+ }
+}
+
+void
+blf_dec(blf_ctx *c, u_int32_t *data, u_int16_t blocks)
+{
+ u_int32_t *d;
+ u_int16_t i;
+
+ d = data;
+ for (i = 0; i < blocks; i++) {
+ Blowfish_decipher(c, d, d + 1);
+ d += 2;
+ }
+}
+
+void
+blf_ecb_encrypt(blf_ctx *c, u_int8_t *data, u_int32_t len)
+{
+ u_int32_t l, r;
+ u_int32_t i;
+
+ for (i = 0; i < len; i += 8) {
+ l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
+ r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
+ Blowfish_encipher(c, &l, &r);
+ data[0] = l >> 24 & 0xff;
+ data[1] = l >> 16 & 0xff;
+ data[2] = l >> 8 & 0xff;
+ data[3] = l & 0xff;
+ data[4] = r >> 24 & 0xff;
+ data[5] = r >> 16 & 0xff;
+ data[6] = r >> 8 & 0xff;
+ data[7] = r & 0xff;
+ data += 8;
+ }
+}
+
+void
+blf_ecb_decrypt(blf_ctx *c, u_int8_t *data, u_int32_t len)
+{
+ u_int32_t l, r;
+ u_int32_t i;
+
+ for (i = 0; i < len; i += 8) {
+ l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
+ r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
+ Blowfish_decipher(c, &l, &r);
+ data[0] = l >> 24 & 0xff;
+ data[1] = l >> 16 & 0xff;
+ data[2] = l >> 8 & 0xff;
+ data[3] = l & 0xff;
+ data[4] = r >> 24 & 0xff;
+ data[5] = r >> 16 & 0xff;
+ data[6] = r >> 8 & 0xff;
+ data[7] = r & 0xff;
+ data += 8;
+ }
+}
+
+void
+blf_cbc_encrypt(blf_ctx *c, u_int8_t *iv, u_int8_t *data, u_int32_t len)
+{
+ u_int32_t l, r;
+ u_int32_t i, j;
+
+ for (i = 0; i < len; i += 8) {
+ for (j = 0; j < 8; j++)
+ data[j] ^= iv[j];
+ l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
+ r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
+ Blowfish_encipher(c, &l, &r);
+ data[0] = l >> 24 & 0xff;
+ data[1] = l >> 16 & 0xff;
+ data[2] = l >> 8 & 0xff;
+ data[3] = l & 0xff;
+ data[4] = r >> 24 & 0xff;
+ data[5] = r >> 16 & 0xff;
+ data[6] = r >> 8 & 0xff;
+ data[7] = r & 0xff;
+ iv = data;
+ data += 8;
+ }
+}
+
+void
+blf_cbc_decrypt(blf_ctx *c, u_int8_t *iva, u_int8_t *data, u_int32_t len)
+{
+ u_int32_t l, r;
+ u_int8_t *iv;
+ u_int32_t i, j;
+
+ iv = data + len - 16;
+ data = data + len - 8;
+ for (i = len - 8; i >= 8; i -= 8) {
+ l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
+ r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
+ Blowfish_decipher(c, &l, &r);
+ data[0] = l >> 24 & 0xff;
+ data[1] = l >> 16 & 0xff;
+ data[2] = l >> 8 & 0xff;
+ data[3] = l & 0xff;
+ data[4] = r >> 24 & 0xff;
+ data[5] = r >> 16 & 0xff;
+ data[6] = r >> 8 & 0xff;
+ data[7] = r & 0xff;
+ for (j = 0; j < 8; j++)
+ data[j] ^= iv[j];
+ iv -= 8;
+ data -= 8;
+ }
+ l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
+ r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
+ Blowfish_decipher(c, &l, &r);
+ data[0] = l >> 24 & 0xff;
+ data[1] = l >> 16 & 0xff;
+ data[2] = l >> 8 & 0xff;
+ data[3] = l & 0xff;
+ data[4] = r >> 24 & 0xff;
+ data[5] = r >> 16 & 0xff;
+ data[6] = r >> 8 & 0xff;
+ data[7] = r & 0xff;
+ for (j = 0; j < 8; j++)
+ data[j] ^= iva[j];
+}
+
+#if 0
+void
+report(u_int32_t data[], u_int16_t len)
+{
+ u_int16_t i;
+ for (i = 0; i < len; i += 2)
+ printf("Block %0hd: %08lx %08lx.\n",
+ i / 2, data[i], data[i + 1]);
+}
+void
+main(void)
+{
+
+ blf_ctx c;
+ char key[] = "AAAAA";
+ char key2[] = "abcdefghijklmnopqrstuvwxyz";
+
+ u_int32_t data[10];
+ u_int32_t data2[] =
+ {0x424c4f57l, 0x46495348l};
+
+ u_int16_t i;
+
+ /* First test */
+ for (i = 0; i < 10; i++)
+ data[i] = i;
+
+ blf_key(&c, (u_int8_t *) key, 5);
+ blf_enc(&c, data, 5);
+ blf_dec(&c, data, 1);
+ blf_dec(&c, data + 2, 4);
+ printf("Should read as 0 - 9.\n");
+ report(data, 10);
+
+ /* Second test */
+ blf_key(&c, (u_int8_t *) key2, strlen(key2));
+ blf_enc(&c, data2, 1);
+ printf("\nShould read as: 0x324ed0fe 0xf413a203.\n");
+ report(data2, 2);
+ blf_dec(&c, data2, 1);
+ report(data2, 2);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/cast.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/cast.c
new file mode 100644
index 0000000..dc21610
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/cast.c
@@ -0,0 +1,778 @@
+/* $OpenBSD: cast.c,v 1.3 2001/06/05 00:12:51 niklas Exp $ */
+/*
+ * CAST-128 in C
+ * Written by Steve Reid <sreid@sea-to-sky.net>
+ * 100% Public Domain - no warranty
+ * Released 1997.10.11
+ */
+
+#include <sys/types.h>
+
+#include <cast.h>
+
+/* CAST S-Boxes */
+
+static const u_int32_t cast_sbox1[256] = {
+ 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A,
+ 0x1E213F2F, 0x9C004DD3, 0x6003E540, 0xCF9FC949,
+ 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675,
+ 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E,
+ 0x28683B6F, 0xC07FD059, 0xFF2379C8, 0x775F50E2,
+ 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D,
+ 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F,
+ 0x2ABE32E1, 0xAA54166B, 0x22568E3A, 0xA2D341D0,
+ 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE,
+ 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7,
+ 0xB82CBAEF, 0xD751D159, 0x6FF7F0ED, 0x5A097A1F,
+ 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935,
+ 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D,
+ 0xB7332290, 0xE93B159F, 0xB48EE411, 0x4BFF345D,
+ 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165,
+ 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50,
+ 0x882240F2, 0x0C6E4F38, 0xA4E4BFD7, 0x4F5BA272,
+ 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE,
+ 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D,
+ 0x57538AD5, 0x6A390493, 0xE63D37E0, 0x2A54F6B3,
+ 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A,
+ 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167,
+ 0x38901091, 0xC6B505EB, 0x84C7CB8C, 0x2AD75A0F,
+ 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291,
+ 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9,
+ 0x6C00B32D, 0x73E2BB14, 0xA0BEBC3C, 0x54623779,
+ 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6,
+ 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2,
+ 0x81383F05, 0x6963C5C8, 0x76CB5AD6, 0xD49974C9,
+ 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511,
+ 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E,
+ 0x31366241, 0x051EF495, 0xAA573B04, 0x4A805D8D,
+ 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E,
+ 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5,
+ 0x6B54BFAB, 0x2B0B1426, 0xAB4CC9D7, 0x449CCD82,
+ 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324,
+ 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC,
+ 0xEADF55B3, 0xD5BD9E98, 0xE31231B2, 0x2AD5AD6C,
+ 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F,
+ 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC,
+ 0x7B5A41F0, 0xD37CFBAD, 0x1B069505, 0x41ECE491,
+ 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D,
+ 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE,
+ 0xE01063DA, 0x4736F464, 0x5AD328D8, 0xB347CC96,
+ 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A,
+ 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A,
+ 0x3F04442F, 0x6188B153, 0xE0397A2E, 0x5727CB79,
+ 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D,
+ 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779,
+ 0x4744EAD4, 0xB11C3274, 0xDD24CB9E, 0x7E1C54BD,
+ 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755,
+ 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6,
+ 0x580304F0, 0xCA042CF1, 0x011A37EA, 0x8DBFAADB,
+ 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9,
+ 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0,
+ 0x7C63B2CF, 0x700B45E1, 0xD5EA50F1, 0x85A92872,
+ 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79,
+ 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C,
+ 0x474D6AD7, 0x7C0C5E5C, 0xD1231959, 0x381B7298,
+ 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E,
+ 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571,
+ 0x962BDA1C, 0xE1E696FF, 0xB141AB08, 0x7CCA89B9,
+ 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D,
+ 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF
+};
+
+static const u_int32_t cast_sbox2[256] = {
+ 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380,
+ 0xFE61CF7A, 0xEEC5207A, 0x55889C94, 0x72FC0651,
+ 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA,
+ 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3,
+ 0xA0B52F7B, 0x59E83605, 0xEE15B094, 0xE9FFD909,
+ 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB,
+ 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B,
+ 0x01420DDB, 0xE4E7EF5B, 0x25A1FF41, 0xE180F806,
+ 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4,
+ 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B,
+ 0xE113C85B, 0xACC40083, 0xD7503525, 0xF7EA615F,
+ 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359,
+ 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21,
+ 0x071F6181, 0x39F7627F, 0x361E3084, 0xE4EB573B,
+ 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D,
+ 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C,
+ 0x10843094, 0x2537A95E, 0xF46F6FFE, 0xA1FF3B1F,
+ 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34,
+ 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D,
+ 0x8A45388C, 0x1D804366, 0x721D9BFD, 0xA58684BB,
+ 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4,
+ 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD,
+ 0xC5D655DD, 0xEB667064, 0x77840B4D, 0xA1B6A801,
+ 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860,
+ 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755,
+ 0xB5625DBF, 0x68561BE6, 0x83CA6B94, 0x2D6ED23B,
+ 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709,
+ 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304,
+ 0x81ED6F61, 0x20E74364, 0xB45E1378, 0xDE18639B,
+ 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B,
+ 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C,
+ 0x488CB402, 0x1BA4FE5B, 0xA4B09F6B, 0x1CA815CF,
+ 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9,
+ 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C,
+ 0xEE41E729, 0x6E1D2D7C, 0x50045286, 0x1E6685F3,
+ 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13,
+ 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9,
+ 0xCDFF33A6, 0xA02B1741, 0x7CBAD9A2, 0x2180036F,
+ 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB,
+ 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6,
+ 0xCDF0B680, 0x17844D3B, 0x31EEF84D, 0x7E0824E4,
+ 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6,
+ 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43,
+ 0xB3FAEC54, 0x157FD7FA, 0xEF8579CC, 0xD152DE58,
+ 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8,
+ 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906,
+ 0xB8DA230C, 0x80823028, 0xDCDEF3C8, 0xD35FB171,
+ 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D,
+ 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89,
+ 0x8B1C34BC, 0x301E16E6, 0x273BE979, 0xB0FFEAA6,
+ 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B,
+ 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4,
+ 0xDC8637A0, 0x16A7D3B1, 0x9FC393B7, 0xA7136EEB,
+ 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6,
+ 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E,
+ 0xDB92F2FB, 0x5EEA29CB, 0x145892F5, 0x91584F7F,
+ 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA,
+ 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249,
+ 0xB284600C, 0xD835731D, 0xDCB1C647, 0xAC4C56EA,
+ 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA,
+ 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD,
+ 0x649DA589, 0xA345415E, 0x5C038323, 0x3E5D3BB9,
+ 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF,
+ 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1
+};
+
+static const u_int32_t cast_sbox3[256] = {
+ 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907,
+ 0x47607FFF, 0x369FE44B, 0x8C1FC644, 0xAECECA90,
+ 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE,
+ 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5,
+ 0x11107D9F, 0x07647DB9, 0xB2E3E4D4, 0x3D4F285E,
+ 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E,
+ 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC,
+ 0x21FFFCEE, 0x825B1BFD, 0x9255C5ED, 0x1257A240,
+ 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E,
+ 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5,
+ 0xA8C01DB7, 0x579FC264, 0x67094F31, 0xF2BD3F5F,
+ 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B,
+ 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99,
+ 0xA197C81C, 0x4A012D6E, 0xC5884A28, 0xCCC36F71,
+ 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F,
+ 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04,
+ 0xA747D2D0, 0x1651192E, 0xAF70BF3E, 0x58C31380,
+ 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82,
+ 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8,
+ 0x8427F4A0, 0x1EAC5790, 0x796FB449, 0x8252DC15,
+ 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504,
+ 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2,
+ 0x23EFE941, 0xA903F12E, 0x60270DF2, 0x0276E4B6,
+ 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176,
+ 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E,
+ 0x842F7D83, 0x340CE5C8, 0x96BBB682, 0x93B4B148,
+ 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D,
+ 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC,
+ 0x8B907CEE, 0xB51FD240, 0xE7C07CE3, 0xE566B4A1,
+ 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341,
+ 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C,
+ 0xF76CEDD9, 0xBDA8229C, 0x127DADAA, 0x438A074E,
+ 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15,
+ 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51,
+ 0x68CC7BFB, 0xD90F2788, 0x12490181, 0x5DE5FFD4,
+ 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F,
+ 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B,
+ 0x6D498623, 0x193CBCFA, 0x27627545, 0x825CF47A,
+ 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392,
+ 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B,
+ 0x285BA1C8, 0x3C62F44F, 0x35C0EAA5, 0xE805D231,
+ 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B,
+ 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889,
+ 0x694BCC11, 0x236A5CAE, 0x12DECA4D, 0x2C3F8CC5,
+ 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67,
+ 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45,
+ 0x3A609437, 0xEC00C9A9, 0x44715253, 0x0A874B49,
+ 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536,
+ 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D,
+ 0x07478CD1, 0x006E1888, 0xA2E53F55, 0xB9E6D4BC,
+ 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D,
+ 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0,
+ 0x947B0001, 0x570075D2, 0xF9BB88F8, 0x8942019E,
+ 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69,
+ 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767,
+ 0xCF1FEBD2, 0x61EFC8C2, 0xF1AC2571, 0xCC8239C2,
+ 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE,
+ 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49,
+ 0x5727C148, 0x2BE98A1D, 0x8AB41738, 0x20E1BE24,
+ 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D,
+ 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0,
+ 0x642B1E31, 0x9C305A00, 0x52BCE688, 0x1B03588A,
+ 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5,
+ 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783
+};
+
+static const u_int32_t cast_sbox4[256] = {
+ 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298,
+ 0x4A4F7BDB, 0x64AD8C57, 0x85510443, 0xFA020ED1,
+ 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120,
+ 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF,
+ 0x28147F5F, 0x4FA2B8CD, 0xC9430040, 0x0CC32220,
+ 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15,
+ 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE,
+ 0x1A05645F, 0x0C13FEFE, 0x081B08CA, 0x05170121,
+ 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701,
+ 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25,
+ 0xCE84FFDF, 0xF5718801, 0x3DD64B04, 0xA26F263B,
+ 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5,
+ 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93,
+ 0xD3772061, 0x11B638E1, 0x72500E03, 0xF80EB2BB,
+ 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746,
+ 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5,
+ 0x4D351805, 0x7F3D5CE3, 0xA6C866C6, 0x5D5BCCA9,
+ 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D,
+ 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB,
+ 0x022083B8, 0x3FB6180C, 0x18F8931E, 0x281658E6,
+ 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C,
+ 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23,
+ 0x69DEAD38, 0x1574CA16, 0xDF871B62, 0x211C40B7,
+ 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003,
+ 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340,
+ 0x557BE8DE, 0x00EAE4A7, 0x0CE5C2EC, 0x4DB4BBA6,
+ 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327,
+ 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119,
+ 0x6E85CB75, 0xBE07C002, 0xC2325577, 0x893FF4EC,
+ 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24,
+ 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205,
+ 0xAAC9548A, 0xECA1D7C7, 0x041AFA32, 0x1D16625A,
+ 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031,
+ 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79,
+ 0x026A4CEB, 0x52437EFF, 0x2F8F76B4, 0x0DF980A5,
+ 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF,
+ 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C,
+ 0x1741A254, 0xE5B6A035, 0x213D42F6, 0x2C1C7C26,
+ 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69,
+ 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB,
+ 0x63315C21, 0x5E0A72EC, 0x49BAFEFD, 0x187908D9,
+ 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7,
+ 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF,
+ 0x71EAE2A1, 0x1F9AF36E, 0xCFCBD12F, 0xC1DE8417,
+ 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3,
+ 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2,
+ 0x6F7DE532, 0x58FD7EB6, 0xD01EE900, 0x24ADFFC2,
+ 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2,
+ 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF,
+ 0x29908415, 0x7FBB977F, 0xAF9EB3DB, 0x29C9ED2A,
+ 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091,
+ 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919,
+ 0x77079103, 0xDEA03AF6, 0x78A8565E, 0xDEE356DF,
+ 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF,
+ 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF,
+ 0xAFE67AFB, 0xF470C4B2, 0xF3E0EB5B, 0xD6CC9876,
+ 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367,
+ 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB,
+ 0xB5676E69, 0x9BD3DDDA, 0xDF7E052F, 0xDB25701C,
+ 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04,
+ 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43,
+ 0x41823979, 0x932BCDF6, 0xB657C34D, 0x4EDFD282,
+ 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E,
+ 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2
+};
+
+static const u_int32_t cast_sbox5[256] = {
+ 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911,
+ 0xB86A7FFF, 0x1DD358F5, 0x44DD9D44, 0x1731167F,
+ 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00,
+ 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A,
+ 0xE6A2E77F, 0xF0C720CD, 0xC4494816, 0xCCF5C180,
+ 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF,
+ 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2,
+ 0x4E40B48D, 0x248EB6FB, 0x8DBA1CFE, 0x41A99B02,
+ 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725,
+ 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A,
+ 0xF2F3F763, 0x68AF8040, 0xED0C9E56, 0x11B4958B,
+ 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7,
+ 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571,
+ 0x0C05372A, 0x578535F2, 0x2261BE02, 0xD642A0C9,
+ 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC,
+ 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981,
+ 0x5C1FF900, 0xFE38D399, 0x0C4EFF0B, 0x062407EA,
+ 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774,
+ 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263,
+ 0xDF65001F, 0x0EC50966, 0xDFDD55BC, 0x29DE0655,
+ 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468,
+ 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2,
+ 0xBCF3F0AA, 0x87AC36E9, 0xE53A7426, 0x01B3D82B,
+ 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910,
+ 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284,
+ 0x636737B6, 0x50F5B616, 0xF24766E3, 0x8ECA36C1,
+ 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4,
+ 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA,
+ 0x26E46695, 0xB7566419, 0xF654EFC5, 0xD08D58B7,
+ 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049,
+ 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE,
+ 0xC62BF3CD, 0x9E0885F9, 0x68CB3E47, 0x086C010F,
+ 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6,
+ 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA,
+ 0x0AB378D5, 0xD951FB0C, 0xDED7DA56, 0x4124BBE4,
+ 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE,
+ 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561,
+ 0xC3DC0280, 0x05687715, 0x646C6BD7, 0x44904DB3,
+ 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6,
+ 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840,
+ 0x76F0AE02, 0x083BE84D, 0x28421C9A, 0x44489406,
+ 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4,
+ 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472,
+ 0x3CA5D717, 0x7D161BBA, 0x9CAD9010, 0xAF462BA2,
+ 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487,
+ 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7,
+ 0x445F7382, 0x175683F4, 0xCDC66A97, 0x70BE0288,
+ 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5,
+ 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2,
+ 0x1C5C1572, 0xF6721B2C, 0x1AD2FFF3, 0x8C25404E,
+ 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78,
+ 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E,
+ 0x44094F85, 0x3F481D87, 0xFCFEAE7B, 0x77B5FF76,
+ 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801,
+ 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0,
+ 0xDF3B0874, 0x95055110, 0x1B5AD7A8, 0xF61ED5AD,
+ 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58,
+ 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0,
+ 0x5CE96C28, 0xE176EDA3, 0x6BAC307F, 0x376829D2,
+ 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20,
+ 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE,
+ 0xF9E0659A, 0xEEB9491D, 0x34010718, 0xBB30CAB8,
+ 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55,
+ 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4
+};
+
+static const u_int32_t cast_sbox6[256] = {
+ 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C,
+ 0x95DB08E7, 0x016843B4, 0xECED5CBC, 0x325553AC,
+ 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9,
+ 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138,
+ 0x33F14961, 0xC01937BD, 0xF506C6DA, 0xE4625E7E,
+ 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367,
+ 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866,
+ 0xA084DB2D, 0x09A8486F, 0xA888614A, 0x2900AF98,
+ 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C,
+ 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072,
+ 0xFD41197E, 0x9305A6B0, 0xE86BE3DA, 0x74BED3CD,
+ 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3,
+ 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53,
+ 0x5C3D9C01, 0x64BDB941, 0x2C0E636A, 0xBA7DD9CD,
+ 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D,
+ 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8,
+ 0x284CAF89, 0xAA928223, 0x9334BE53, 0x3B3A21BF,
+ 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9,
+ 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807,
+ 0x5B7C5ECC, 0x221DB3A6, 0x9A69A02F, 0x68818A54,
+ 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A,
+ 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387,
+ 0x53BDDB65, 0xE76FFBE7, 0xE967FD78, 0x0BA93563,
+ 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC,
+ 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0,
+ 0xE81F994F, 0x9528CD89, 0xFD339FED, 0xB87834BF,
+ 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE,
+ 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF,
+ 0x4EC75B95, 0x24F2C3C0, 0x42D15D99, 0xCD0D7FA0,
+ 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F,
+ 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2,
+ 0x372B74AF, 0x692573E4, 0xE9A9D848, 0xF3160289,
+ 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853,
+ 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950,
+ 0x36F73523, 0x4CFB6E87, 0x7DA4CEC0, 0x6C152DAA,
+ 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F,
+ 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9,
+ 0x2B05D08D, 0x48B9D585, 0xDC049441, 0xC8098F9B,
+ 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751,
+ 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE,
+ 0xBF32679D, 0xD45B5B75, 0xB353FD00, 0xCBB0E358,
+ 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13,
+ 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397,
+ 0x47CF8E7A, 0xB6C85283, 0x3CC2ACFB, 0x3FC06976,
+ 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459,
+ 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0,
+ 0x3007CD3E, 0x74719EEF, 0xDC872681, 0x073340D4,
+ 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891,
+ 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F,
+ 0x6FE4AC98, 0xB173ECC0, 0xBC60B42A, 0x953498DA,
+ 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB,
+ 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC,
+ 0xE8816F4A, 0x3814F200, 0xA3F94043, 0x9C7A54C2,
+ 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084,
+ 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB,
+ 0xBA5AC7B5, 0xB6F6DEAF, 0x3A479C3A, 0x5302DA25,
+ 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B,
+ 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121,
+ 0xB81A928A, 0x60ED5869, 0x97C55B96, 0xEAEC991B,
+ 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5,
+ 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855,
+ 0xD36B4CF1, 0xF544EDEB, 0xB0E93524, 0xBEBB8FBD,
+ 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454,
+ 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F
+};
+
+static const u_int32_t cast_sbox7[256] = {
+ 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693,
+ 0x2A8D7F6F, 0xAB9BC912, 0xDE6008A1, 0x2028DA1F,
+ 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82,
+ 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE,
+ 0xA05FBCF6, 0xCD4181E9, 0xE150210C, 0xE24EF1BD,
+ 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43,
+ 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F,
+ 0x089766BE, 0xBAEEADF4, 0x1286BECF, 0xB6EACB19,
+ 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9,
+ 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2,
+ 0x107789BE, 0xB3B2E9CE, 0x0502AA8F, 0x0BC0351E,
+ 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516,
+ 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83,
+ 0x334266CE, 0x8C9341B7, 0xD0D854C0, 0xCB3A6C88,
+ 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E,
+ 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816,
+ 0x0A961288, 0xE1A5C06E, 0x13749E67, 0x72FC081A,
+ 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756,
+ 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F,
+ 0xBC8EC511, 0x38BC46E9, 0xC6E6FA14, 0xBAE8584A,
+ 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B,
+ 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264,
+ 0x92544A8B, 0x009B4FC3, 0xABA68CED, 0x9AC96F78,
+ 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688,
+ 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D,
+ 0xF7DEBB85, 0x61FE033C, 0x16746233, 0x3C034C28,
+ 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802,
+ 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3,
+ 0x0C4FB99A, 0xBB325778, 0x3EC6D97B, 0x6E77A6A9,
+ 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7,
+ 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302,
+ 0xB96D8C32, 0xEBD4E7BE, 0xBE8B9D2D, 0x7979FB06,
+ 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858,
+ 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033,
+ 0xF28EBFB0, 0xF5B9C310, 0xA0EAC280, 0x08B9767A,
+ 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A,
+ 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4,
+ 0x826D2BEF, 0x4EEB8476, 0x488DCF25, 0x36C9D566,
+ 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF,
+ 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509,
+ 0xF22B017D, 0xA4173F70, 0xDD1E16C3, 0x15E0D7F9,
+ 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962,
+ 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C,
+ 0x93D29A22, 0xE32DBF9A, 0x058745B9, 0x3453DC1E,
+ 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07,
+ 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C,
+ 0x66626C1C, 0x7154C24C, 0xEA082B2A, 0x93EB2939,
+ 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C,
+ 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E,
+ 0xD3A0C108, 0xA1E7160E, 0xE4F2DFA6, 0x693ED285,
+ 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378,
+ 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301,
+ 0xC79F022F, 0x3C997E7E, 0x5E4F9504, 0x3FFAFBBD,
+ 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE,
+ 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567,
+ 0x5592A33D, 0xB5229301, 0xCFD2A87F, 0x60AEB767,
+ 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2,
+ 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647,
+ 0x97FD61A9, 0xEA7759F4, 0x2D57539D, 0x569A58CF,
+ 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914,
+ 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2,
+ 0x3FFA50BC, 0x3D40F021, 0xC3C0BDAE, 0x4958C24C,
+ 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA,
+ 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3
+};
+
+static const u_int32_t cast_sbox8[256] = {
+ 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095,
+ 0x7789F8B7, 0xE6C1121B, 0x0E241600, 0x052CE8B5,
+ 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174,
+ 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC,
+ 0xDE9ADEB1, 0x0A0CC32C, 0xBE197029, 0x84A00940,
+ 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD,
+ 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42,
+ 0xC7ECE831, 0x3F8F95E7, 0x72DF191B, 0x7580330D,
+ 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164,
+ 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2,
+ 0x12A8DDEC, 0xFDAA335D, 0x176F43E8, 0x71FB46D4,
+ 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862,
+ 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0,
+ 0x4CFDE06F, 0xC28EC4B8, 0x57E8726E, 0x647A78FC,
+ 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6,
+ 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C,
+ 0xBBD35049, 0x2998DF04, 0x980CF42A, 0x9B6DF491,
+ 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E,
+ 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B,
+ 0x3CF1D2E2, 0x19B47A38, 0x424F7618, 0x35856039,
+ 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8,
+ 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8,
+ 0x7170C608, 0x2D5E3354, 0xD4DE495A, 0x64C6D006,
+ 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42,
+ 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564,
+ 0xF8D7E54E, 0x3E378160, 0x7895CDA5, 0x859C15A5,
+ 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB,
+ 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472,
+ 0x835FFCB8, 0x6DF4C1F2, 0x96F5B195, 0xFD0AF0FC,
+ 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225,
+ 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8,
+ 0xC4618187, 0xEA7A6E98, 0x7CD16EFC, 0x1436876C,
+ 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441,
+ 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB,
+ 0xA842EEDF, 0xFDBA60B4, 0xF1907B75, 0x20E3030F,
+ 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054,
+ 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504,
+ 0xF1E47D8D, 0x844A1BE5, 0xBAE7DFDC, 0x42CBDA70,
+ 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C,
+ 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC,
+ 0x77853B53, 0x37EFFCB5, 0xC5068778, 0xE580B3E6,
+ 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C,
+ 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD,
+ 0xDD06CAA2, 0x37DF932B, 0xC4248289, 0xACF3EBC3,
+ 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4,
+ 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4,
+ 0xE87B40E4, 0xE98EA084, 0x5889E9E1, 0xEFD390FC,
+ 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101,
+ 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA,
+ 0x646F1282, 0x7523D24A, 0xE0779695, 0xF9C17A8F,
+ 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF,
+ 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E,
+ 0x11403092, 0x00DA6D77, 0x4A0CDD61, 0xAD1F4603,
+ 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A,
+ 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37,
+ 0x2DE705CA, 0x8951570F, 0xDF09822B, 0xBD691A6C,
+ 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819,
+ 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384,
+ 0x5938FA0F, 0x42399EF3, 0x36997B07, 0x0E84093D,
+ 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C,
+ 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347,
+ 0x589E8D82, 0x0D2059D1, 0xA466BB1E, 0xF8DA0A82,
+ 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D,
+ 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E
+};
+
+/* Macros to access 8-bit bytes out of a 32-bit word */
+#define U8a(x) ( (u_int8_t) (x>>24) )
+#define U8b(x) ( (u_int8_t) ((x>>16)&255) )
+#define U8c(x) ( (u_int8_t) ((x>>8)&255) )
+#define U8d(x) ( (u_int8_t) ((x)&255) )
+
+/* Circular left shift */
+#define ROL(x, n) ( ((x)<<(n)) | ((x)>>(32-(n))) )
+
+/* CAST-128 uses three different round functions */
+#define F1(l, r, i) \
+ t = ROL(key->xkey[i] + r, key->xkey[i+16]); \
+ l ^= ((cast_sbox1[U8a(t)] ^ cast_sbox2[U8b(t)]) - \
+ cast_sbox3[U8c(t)]) + cast_sbox4[U8d(t)];
+#define F2(l, r, i) \
+ t = ROL(key->xkey[i] ^ r, key->xkey[i+16]); \
+ l ^= ((cast_sbox1[U8a(t)] - cast_sbox2[U8b(t)]) + \
+ cast_sbox3[U8c(t)]) ^ cast_sbox4[U8d(t)];
+#define F3(l, r, i) \
+ t = ROL(key->xkey[i] - r, key->xkey[i+16]); \
+ l ^= ((cast_sbox1[U8a(t)] + cast_sbox2[U8b(t)]) ^ \
+ cast_sbox3[U8c(t)]) - cast_sbox4[U8d(t)];
+
+
+/***** Encryption Function *****/
+
+void cast_encrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock)
+{
+u_int32_t t, l, r;
+
+ /* Get inblock into l,r */
+ l = ((u_int32_t)inblock[0] << 24) | ((u_int32_t)inblock[1] << 16) |
+ ((u_int32_t)inblock[2] << 8) | (u_int32_t)inblock[3];
+ r = ((u_int32_t)inblock[4] << 24) | ((u_int32_t)inblock[5] << 16) |
+ ((u_int32_t)inblock[6] << 8) | (u_int32_t)inblock[7];
+ /* Do the work */
+ F1(l, r, 0);
+ F2(r, l, 1);
+ F3(l, r, 2);
+ F1(r, l, 3);
+ F2(l, r, 4);
+ F3(r, l, 5);
+ F1(l, r, 6);
+ F2(r, l, 7);
+ F3(l, r, 8);
+ F1(r, l, 9);
+ F2(l, r, 10);
+ F3(r, l, 11);
+ /* Only do full 16 rounds if key length > 80 bits */
+ if (key->rounds > 12) {
+ F1(l, r, 12);
+ F2(r, l, 13);
+ F3(l, r, 14);
+ F1(r, l, 15);
+ }
+ /* Put l,r into outblock */
+ outblock[0] = U8a(r);
+ outblock[1] = U8b(r);
+ outblock[2] = U8c(r);
+ outblock[3] = U8d(r);
+ outblock[4] = U8a(l);
+ outblock[5] = U8b(l);
+ outblock[6] = U8c(l);
+ outblock[7] = U8d(l);
+ /* Wipe clean */
+ t = l = r = 0;
+}
+
+
+/***** Decryption Function *****/
+
+void cast_decrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock)
+{
+u_int32_t t, l, r;
+
+ /* Get inblock into l,r */
+ r = ((u_int32_t)inblock[0] << 24) | ((u_int32_t)inblock[1] << 16) |
+ ((u_int32_t)inblock[2] << 8) | (u_int32_t)inblock[3];
+ l = ((u_int32_t)inblock[4] << 24) | ((u_int32_t)inblock[5] << 16) |
+ ((u_int32_t)inblock[6] << 8) | (u_int32_t)inblock[7];
+ /* Do the work */
+ /* Only do full 16 rounds if key length > 80 bits */
+ if (key->rounds > 12) {
+ F1(r, l, 15);
+ F3(l, r, 14);
+ F2(r, l, 13);
+ F1(l, r, 12);
+ }
+ F3(r, l, 11);
+ F2(l, r, 10);
+ F1(r, l, 9);
+ F3(l, r, 8);
+ F2(r, l, 7);
+ F1(l, r, 6);
+ F3(r, l, 5);
+ F2(l, r, 4);
+ F1(r, l, 3);
+ F3(l, r, 2);
+ F2(r, l, 1);
+ F1(l, r, 0);
+ /* Put l,r into outblock */
+ outblock[0] = U8a(l);
+ outblock[1] = U8b(l);
+ outblock[2] = U8c(l);
+ outblock[3] = U8d(l);
+ outblock[4] = U8a(r);
+ outblock[5] = U8b(r);
+ outblock[6] = U8c(r);
+ outblock[7] = U8d(r);
+ /* Wipe clean */
+ t = l = r = 0;
+}
+
+
+/***** Key Schedual *****/
+
+void cast_setkey(cast_key* key, u_int8_t* rawkey, int keybytes)
+{
+u_int32_t t[4], z[4], x[4];
+int i;
+
+ /* Set number of rounds to 12 or 16, depending on key length */
+ key->rounds = (keybytes <= 10 ? 12 : 16);
+
+ /* Copy key to workspace x */
+ for (i = 0; i < 4; i++) {
+ x[i] = 0;
+ if ((i*4+0) < keybytes) x[i] = (u_int32_t)rawkey[i*4+0] << 24;
+ if ((i*4+1) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+1] << 16;
+ if ((i*4+2) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+2] << 8;
+ if ((i*4+3) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+3];
+ }
+ /* Generate 32 subkeys, four at a time */
+ for (i = 0; i < 32; i+=4) {
+ switch (i & 4) {
+ case 0:
+ t[0] = z[0] = x[0] ^ cast_sbox5[U8b(x[3])] ^
+ cast_sbox6[U8d(x[3])] ^ cast_sbox7[U8a(x[3])] ^
+ cast_sbox8[U8c(x[3])] ^ cast_sbox7[U8a(x[2])];
+ t[1] = z[1] = x[2] ^ cast_sbox5[U8a(z[0])] ^
+ cast_sbox6[U8c(z[0])] ^ cast_sbox7[U8b(z[0])] ^
+ cast_sbox8[U8d(z[0])] ^ cast_sbox8[U8c(x[2])];
+ t[2] = z[2] = x[3] ^ cast_sbox5[U8d(z[1])] ^
+ cast_sbox6[U8c(z[1])] ^ cast_sbox7[U8b(z[1])] ^
+ cast_sbox8[U8a(z[1])] ^ cast_sbox5[U8b(x[2])];
+ t[3] = z[3] = x[1] ^ cast_sbox5[U8c(z[2])] ^
+ cast_sbox6[U8b(z[2])] ^ cast_sbox7[U8d(z[2])] ^
+ cast_sbox8[U8a(z[2])] ^ cast_sbox6[U8d(x[2])];
+ break;
+ case 4:
+ t[0] = x[0] = z[2] ^ cast_sbox5[U8b(z[1])] ^
+ cast_sbox6[U8d(z[1])] ^ cast_sbox7[U8a(z[1])] ^
+ cast_sbox8[U8c(z[1])] ^ cast_sbox7[U8a(z[0])];
+ t[1] = x[1] = z[0] ^ cast_sbox5[U8a(x[0])] ^
+ cast_sbox6[U8c(x[0])] ^ cast_sbox7[U8b(x[0])] ^
+ cast_sbox8[U8d(x[0])] ^ cast_sbox8[U8c(z[0])];
+ t[2] = x[2] = z[1] ^ cast_sbox5[U8d(x[1])] ^
+ cast_sbox6[U8c(x[1])] ^ cast_sbox7[U8b(x[1])] ^
+ cast_sbox8[U8a(x[1])] ^ cast_sbox5[U8b(z[0])];
+ t[3] = x[3] = z[3] ^ cast_sbox5[U8c(x[2])] ^
+ cast_sbox6[U8b(x[2])] ^ cast_sbox7[U8d(x[2])] ^
+ cast_sbox8[U8a(x[2])] ^ cast_sbox6[U8d(z[0])];
+ break;
+ }
+ switch (i & 12) {
+ case 0:
+ case 12:
+ key->xkey[i+0] = cast_sbox5[U8a(t[2])] ^ cast_sbox6[U8b(t[2])] ^
+ cast_sbox7[U8d(t[1])] ^ cast_sbox8[U8c(t[1])];
+ key->xkey[i+1] = cast_sbox5[U8c(t[2])] ^ cast_sbox6[U8d(t[2])] ^
+ cast_sbox7[U8b(t[1])] ^ cast_sbox8[U8a(t[1])];
+ key->xkey[i+2] = cast_sbox5[U8a(t[3])] ^ cast_sbox6[U8b(t[3])] ^
+ cast_sbox7[U8d(t[0])] ^ cast_sbox8[U8c(t[0])];
+ key->xkey[i+3] = cast_sbox5[U8c(t[3])] ^ cast_sbox6[U8d(t[3])] ^
+ cast_sbox7[U8b(t[0])] ^ cast_sbox8[U8a(t[0])];
+ break;
+ case 4:
+ case 8:
+ key->xkey[i+0] = cast_sbox5[U8d(t[0])] ^ cast_sbox6[U8c(t[0])] ^
+ cast_sbox7[U8a(t[3])] ^ cast_sbox8[U8b(t[3])];
+ key->xkey[i+1] = cast_sbox5[U8b(t[0])] ^ cast_sbox6[U8a(t[0])] ^
+ cast_sbox7[U8c(t[3])] ^ cast_sbox8[U8d(t[3])];
+ key->xkey[i+2] = cast_sbox5[U8d(t[1])] ^ cast_sbox6[U8c(t[1])] ^
+ cast_sbox7[U8a(t[2])] ^ cast_sbox8[U8b(t[2])];
+ key->xkey[i+3] = cast_sbox5[U8b(t[1])] ^ cast_sbox6[U8a(t[1])] ^
+ cast_sbox7[U8c(t[2])] ^ cast_sbox8[U8d(t[2])];
+ break;
+ }
+ switch (i & 12) {
+ case 0:
+ key->xkey[i+0] ^= cast_sbox5[U8c(z[0])];
+ key->xkey[i+1] ^= cast_sbox6[U8c(z[1])];
+ key->xkey[i+2] ^= cast_sbox7[U8b(z[2])];
+ key->xkey[i+3] ^= cast_sbox8[U8a(z[3])];
+ break;
+ case 4:
+ key->xkey[i+0] ^= cast_sbox5[U8a(x[2])];
+ key->xkey[i+1] ^= cast_sbox6[U8b(x[3])];
+ key->xkey[i+2] ^= cast_sbox7[U8d(x[0])];
+ key->xkey[i+3] ^= cast_sbox8[U8d(x[1])];
+ break;
+ case 8:
+ key->xkey[i+0] ^= cast_sbox5[U8b(z[2])];
+ key->xkey[i+1] ^= cast_sbox6[U8a(z[3])];
+ key->xkey[i+2] ^= cast_sbox7[U8c(z[0])];
+ key->xkey[i+3] ^= cast_sbox8[U8c(z[1])];
+ break;
+ case 12:
+ key->xkey[i+0] ^= cast_sbox5[U8d(x[0])];
+ key->xkey[i+1] ^= cast_sbox6[U8d(x[1])];
+ key->xkey[i+2] ^= cast_sbox7[U8a(x[2])];
+ key->xkey[i+3] ^= cast_sbox8[U8b(x[3])];
+ break;
+ }
+ if (i >= 16) {
+ key->xkey[i+0] &= 31;
+ key->xkey[i+1] &= 31;
+ key->xkey[i+2] &= 31;
+ key->xkey[i+3] &= 31;
+ }
+ }
+ /* Wipe clean */
+ for (i = 0; i < 4; i++) {
+ t[i] = x[i] = z[i] = 0;
+ }
+}
+
+/* Made in Canada */
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/md5.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/md5.c
new file mode 100644
index 0000000..8a7a483
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/md5.c
@@ -0,0 +1,392 @@
+/* $OpenBSD: md5.c,v 1.3 2002/06/14 21:34:58 todd Exp $ */
+
+/*
+ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
+ * changes to accommodate it in the kernel by ji.
+ */
+
+/* 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 "md5.h"
+
+#ifndef WIN32
+#include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
+#endif
+
+#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], 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 */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)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], (POINTER)&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];
+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/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/sha1.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/sha1.c
new file mode 100644
index 0000000..da63563
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/sha1.c
@@ -0,0 +1,173 @@
+/* $OpenBSD: sha1.c,v 1.2 2001/01/28 22:38:48 niklas Exp $ */
+
+/*
+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 "sha1.h"
+#ifndef WIN32
+ #include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
+#endif
+
+#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(unsigned long state[5], unsigned char buffer[64])
+{
+unsigned long a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ unsigned long l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static CHAR64LONG16 workspace;
+ block = &workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (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;
+}
+
+
+/* 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, unsigned char* data, unsigned int len)
+{
+unsigned int i;
+unsigned long j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j) context->count[1] += (len>>29)+1;
+ 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 long i, j;
+unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 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 */
+ i = j = 0;
+ memset(context->buffer, '\0', 64);
+ memset(context->state, '\0', 20);
+ memset(context->count, '\0', 8);
+ memset(&finalcount, '\0', 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcat.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcat.c
new file mode 100644
index 0000000..3b55428
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcat.c
@@ -0,0 +1,62 @@
+/* $OpenBSD: strlcat.c,v 1.3 2003/06/17 21:56:24 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcat.c,v 1.3 2003/06/17 21:56:24 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcpy.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcpy.c
new file mode 100644
index 0000000..ef7db13
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcpy.c
@@ -0,0 +1,58 @@
+/* $OpenBSD: strlcpy.c,v 1.3 2003/06/17 21:56:24 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.3 2003/06/17 21:56:24 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/md5.h b/keyexchange/isakmpd-20041012/sysdep/common/md5.h
new file mode 100644
index 0000000..ea703c3
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/md5.h
@@ -0,0 +1,73 @@
+/* $OpenBSD: md5.h,v 1.2 2001/01/28 22:38:47 niklas Exp $ */
+
+/* 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;
+
+/* 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
+
+
+/* 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 *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+#define _MD5_H_
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/pcap.h b/keyexchange/isakmpd-20041012/sysdep/common/pcap.h
new file mode 100644
index 0000000..21117d8
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/pcap.h
@@ -0,0 +1,69 @@
+/* $OpenBSD: pcap.h,v 1.2 2002/05/10 15:09:00 ho Exp $ */
+
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * 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 Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ *
+ * @(#) $Header: /cvs/src/sbin/isakmpd/sysdep/common/pcap.h,v 1.2 2002/05/10 15:09:00 ho Exp $ (LBL)
+ */
+
+#ifndef lib_pcap_h
+#define lib_pcap_h
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+#define DLT_LOOP 12 /* from /usr/include/net/bpf.h */
+
+struct pcap_file_header {
+ u_int32_t magic;
+ u_int16_t version_major;
+ u_int16_t version_minor;
+ int32_t thiszone; /* gmt to local correction */
+ u_int32_t sigfigs; /* accuracy of timestamps */
+ u_int32_t snaplen; /* max length saved portion of each pkt */
+ u_int32_t linktype; /* data link type (DLT_*) */
+};
+
+struct pcap_timeval {
+ int32_t tv_sec; /* seconds */
+ int32_t tv_usec; /* microseconds */
+};
+
+struct pcap_pkthdr {
+ struct pcap_timeval ts; /* time stamp */
+ u_int32_t caplen; /* length of portion present */
+ u_int32_t len; /* length this packet (off wire) */
+};
+
+#endif /* lib_pcap_h */
diff --git a/keyexchange/isakmpd-20041012/sysdep/common/sha1.h b/keyexchange/isakmpd-20041012/sysdep/common/sha1.h
new file mode 100644
index 0000000..c706c6e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/common/sha1.h
@@ -0,0 +1,18 @@
+/* $OpenBSD: sha1.h,v 1.2 2001/01/28 22:38:47 niklas Exp $ */
+
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+
+typedef struct {
+ unsigned long state[5];
+ unsigned long count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
diff --git a/keyexchange/isakmpd-20041012/sysdep/darwin/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/darwin/GNUmakefile.sysdep
new file mode 100644
index 0000000..09f888d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/darwin/GNUmakefile.sysdep
@@ -0,0 +1,48 @@
+# $OpenBSD: GNUmakefile.sysdep,v 1.3 2004/06/26 03:40:57 mcbride Exp $
+
+#
+# Copyright (c) 1999,2002 Håkan Olsson. All rights reserved.
+# Copyright (c) 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+LDADD+= -lipsec
+
+# gcc under MacOS X does not seem to like building things -static
+LDSTATIC=
+
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
+CFLAGS+= -DHAVE_GETIFADDRS
+
+FEATURES= debug tripledes des blowdish cast ec aggressive x509
+FEATURES+= rawkey isakmp_cfg
+# Not yet
+#FEATURES+= policy
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
diff --git a/keyexchange/isakmpd-20041012/sysdep/darwin/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/darwin/Makefile.sysdep
new file mode 100644
index 0000000..834347d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/darwin/Makefile.sysdep
@@ -0,0 +1,45 @@
+# $OpenBSD: Makefile.sysdep,v 1.3 2004/06/26 03:40:57 mcbride Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 INN 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# Override default features
+FEATURES= tripledes des blowfish cast x509 ec aggressive debug
+FEATURES+= rawkey isakmp_cfg
+
+LDADD+= -lipsec
+
+CFLAGS+= -DHAVE_GETIFADDRS -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
+
+obj:
+ mkdir obj
diff --git a/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep-os.h
new file mode 100644
index 0000000..28755bc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep-os.h
@@ -0,0 +1,81 @@
+/* $OpenBSD: sysdep-os.h,v 1.3 2003/08/06 11:23:11 markus Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2002 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _SYSDEP_OS_H_
+
+#define _SYSDEP_OS_H_
+
+#define KAME
+
+#include <netinet6/ipsec.h>
+
+typedef u_int32_t socklen_t;
+
+#ifndef CPI_RESERVED_MAX
+#define CPI_RESERVED_MIN 1
+#define CPI_RESERVED_MAX 255
+#define CPI_PRIVATE_MIN 61440
+#define CPI_PRIVATE_MAX 65536
+#endif
+
+#if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC)
+#define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC
+#endif
+
+#if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC)
+#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC
+#endif
+
+#if 1
+/* OpenSSL differs from OpenBSD very slightly... */
+
+#define MD5Init MD5_Init
+#define MD5Update MD5_Update
+#define MD5Final MD5_Final
+
+#define SHA1Init SHA1_Init
+#define SHA1Update SHA1_Update
+#define SHA1Final SHA1_Final
+#define SHA1_CTX SHA_CTX
+
+#define cast_key CAST_KEY
+#define cast_setkey(k, d, l) CAST_set_key ((k), (l), (d))
+#define cast_encrypt(k, i, o) do { \
+ memcpy ((o), (i), BLOCKSIZE); \
+ CAST_encrypt ((CAST_LONG *)(o), (k)); \
+} while (0)
+#define cast_decrypt(k, i, o) do { \
+ memcpy ((o), (i), BLOCKSIZE); \
+ CAST_decrypt ((CAST_LONG *)(o), (k)); \
+} while (0)
+#endif
+
+#endif /* _SYSDEP_OS_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep.c
new file mode 100644
index 0000000..cd61d5a
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep.c
@@ -0,0 +1,223 @@
+/* $OpenBSD: sysdep.c,v 1.3 2004/08/10 15:59:10 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "util.h"
+
+#ifdef NEED_SYSDEP_APP
+#include "app.h"
+#include "conf.h"
+#include "ipsec.h"
+
+#ifdef USE_PF_KEY_V2
+#include "pf_key_v2.h"
+#define KEY_API(x) pf_key_v2_##x
+#endif
+
+#endif /* NEED_SYSDEP_APP */
+#include "log.h"
+
+extern char *__progname;
+
+/*
+ * An as strong as possible random number generator, reverting to a
+ * deterministic pseudo-random one if regrand is set.
+ */
+u_int32_t
+sysdep_random ()
+{
+ return random();
+}
+
+/* Return the basename of the command used to invoke us. */
+char *
+sysdep_progname ()
+{
+ return __progname;
+}
+
+/* Return the length of the sockaddr struct. */
+u_int8_t
+sysdep_sa_len (struct sockaddr *sa)
+{
+ return sa->sa_len;
+}
+
+/* As regress/ use this file I protect the sysdep_app_* stuff like this. */
+#ifdef NEED_SYSDEP_APP
+/*
+ * Prepare the application we negotiate SAs for (i.e. the IPsec stack)
+ * for communication. We return a file descriptor useable to select(2) on.
+ */
+int
+sysdep_app_open ()
+{
+ return KEY_API(open) ();
+}
+
+/*
+ * When select(2) has noticed our application needs attendance, this is what
+ * gets called. FD is the file descriptor causing the alarm.
+ */
+void
+sysdep_app_handler (int fd)
+{
+ KEY_API (handler) (fd);
+}
+
+/* Check that the connection named NAME is active, or else make it active. */
+void
+sysdep_connection_check (char *name)
+{
+ KEY_API (connection_check) (name);
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ if (app_none)
+ {
+ *sz = IPSEC_SPI_SIZE;
+ /* XXX should be random instead I think. */
+ return strdup ("\x12\x34\x56\x78");
+ }
+ return KEY_API (get_spi) (sz, proto, src, dst, seq);
+}
+
+struct sa_kinfo *
+sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
+ struct sockaddr *dst)
+{
+ if (app_none)
+ return 0;
+ /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */
+ return 0;
+}
+
+/* Force communication on socket FD to go in the clear. */
+int
+sysdep_cleartext (int fd, int af)
+{
+ char *buf;
+ char *policy[] = { "in bypass", "out bypass", NULL };
+ char **p;
+ int ipp;
+
+ if (app_none)
+ return 0;
+
+ switch (af)
+ {
+ case AF_INET:
+ ipp = IPPROTO_IP;
+ break;
+ case AF_INET6:
+ ipp = IPPROTO_IPV6;
+ break;
+ default:
+ log_print ("sysdep_cleartext: unsupported protocol family %d", af);
+ return -1;
+ }
+
+ /*
+ * Need to bypass system security policy, so I can send and
+ * receive key management datagrams in the clear.
+ */
+
+ for (p = policy; p && *p; p++)
+ {
+ buf = ipsec_set_policy (*p, strlen(*p));
+ if (buf == NULL)
+ {
+ log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror());
+ return -1;
+ }
+
+ if (setsockopt(fd, ipp, IP_IPSEC_POLICY, buf,
+ ipsec_get_policylen(buf)) < 0)
+ {
+ log_error ("sysdep_cleartext: "
+ "setsockopt (%d, IPPROTO_IP, IP_IPSEC_POLICY, ...) failed",
+ fd);
+ return -1;
+ }
+ free(buf);
+ }
+
+ return 0;
+}
+
+int
+sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (delete_spi) (sa, proto, incoming);
+}
+
+int
+sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (enable_sa) (sa, isakmp_sa);
+}
+
+int
+sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (group_spis) (sa, proto1, proto2, incoming);
+}
+
+int
+sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/freebsd/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/freebsd/GNUmakefile.sysdep
new file mode 100644
index 0000000..618ef5f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freebsd/GNUmakefile.sysdep
@@ -0,0 +1,61 @@
+# $OpenBSD: GNUmakefile.sysdep,v 1.6 2004/06/26 03:40:57 mcbride Exp $
+
+#
+# Copyright (c) 1999 Håkan Olsson. All rights reserved.
+# Copyright (c) 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+LIBGMP:= /usr/lib/libgmp.a
+LIBCRYPTO:= /usr/lib/libcrypto.a
+LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep
+LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a
+
+LDADD+= -lgmp ${LIBSYSDEP}
+DPADD+= ${LIBGMP} ${LIBSYSDEP}
+
+FEATURES= debug tripledes des blowdish cast ec aggressive
+# Not yet
+#FEATURES+= policy x509
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
+
+# hack libsysdep.a dependency
+${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}:
+ cd ${LIBSYSDEPDIR} &&
+ ${MAKE} --no-print-directory ${MAKEFLAGS} \
+ CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS}
+
+depend: ${LIBSYSDEPDIR}/.depend
+
+ifeq ($(findstring clean, $(MAKECMDGOALS)), clean)
+SUBDIR+= sysdep/common/libsysdep
+MAKEFLAGS+= --no-print-directory
+endif
+
diff --git a/keyexchange/isakmpd-20041012/sysdep/freebsd/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/freebsd/Makefile.sysdep
new file mode 100644
index 0000000..03dae50
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freebsd/Makefile.sysdep
@@ -0,0 +1,77 @@
+# $OpenBSD: Makefile.sysdep,v 1.10 2004/06/26 03:40:57 mcbride Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 INN 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# Override default features
+FEATURES= tripledes des blowfish cast x509 ec aggressive debug
+FEATURES+= rawkey
+# Not yet
+#FEATURES+= policy isakmp_cfg
+
+.if defined(TOPDIR)
+LIBSYSDEPDIR= ${TOPDIR}/sysdep/common/libsysdep
+.else
+LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep
+.endif
+
+LDADD+= -lgmp ${LIBSYSDEPDIR}/libsysdep.a -lipsec -L/usr/local/lib
+DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a
+
+CFLAGS+= -DHAVE_GETIFADDRS \
+ -I${.CURDIR}/sysdep/common -I/usr/include \
+ -I/usr/local/include -I/usr/local/include/openssl
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
+
+# This is a hack in order to make sure libsysdep is built before the
+# linkstage of isakmpd. As a side effect the link is always done even if
+# not necessary. Well, I just don't care.
+GENERATED+= sysdep-target
+sysdep-target:
+ cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS}
+
+# Kludge around much strange behaviour in /usr/share/mk/bsd.*/mk, don't build certpatch
+SUBDIR=
+
+.if make(clean)
+SUBDIR+= sysdep/common/libsysdep
+.endif
+
+# Kludge around bug in /usr/share/mk/bsd.subdir.mk
+NO_REGRESS= defined
+
+# Kludge around bug/feature in /usr/share/mk/bsd.man.mk
+MAN8= isakmpd.8
+MAN5= isakmpd.conf.5 isakmpd.policy.5
+
+obj:
+ mkdir obj
diff --git a/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep-os.h
new file mode 100644
index 0000000..cecc2c2
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep-os.h
@@ -0,0 +1,79 @@
+/* $OpenBSD: sysdep-os.h,v 1.5 2003/06/03 14:53:11 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _SYSDEP_OS_H_
+
+#define _SYSDEP_OS_H_
+
+#define KAME
+
+#include <netinet6/ipsec.h>
+
+#if ( __FreeBSD_cc_version < 440000 )
+/* We need in_addr_t & in_port_t */
+typedef u_int32_t in_addr_t;
+typedef u_int16_t in_port_t;
+#endif
+#if ( __FreeBSD__ < 4 )
+/* We need socklen_t too. */
+typedef u_int32_t socklen_t;
+#endif
+
+/* Map extensions to values from /usr/include/net/pfkeyv2.h */
+#if ( SADB_EALG_MAX == 7 )
+/* FreeBSD 4.2 */
+#define SADB_X_EALG_BLF SADB_EALG_BLOWFISHCBC
+#define SADB_X_EALG_CAST SADB_EALG_CAST128CBC
+#else if ( SADB_EALG_MAX == 12 )
+/* FreeBSD 4.4 */
+#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC
+#define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC
+#endif
+
+#if 0
+/* OpenSSL differs from OpenBSD very slightly... */
+
+#define SHA1Init SHA1_Init
+#define SHA1Update SHA1_Update
+#define SHA1Final SHA1_Final
+
+#define cast_key CAST_KEY
+#define cast_setkey(k, d, l) CAST_set_key ((k), (l), (d))
+#define cast_encrypt(k, i, o) do { \
+ memcpy ((o), (i), BLOCKSIZE); \
+ CAST_encrypt ((CAST_LONG *)(o), (k)); \
+}
+#define cast_decrypt(k, i, o) do { \
+ memcpy ((o), (i), BLOCKSIZE); \
+ CAST_decrypt ((CAST_LONG *)(o), (k)); \
+}
+#endif
+
+#endif /* _SYSDEP_OS_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep.c
new file mode 100644
index 0000000..2679fc8
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep.c
@@ -0,0 +1,228 @@
+/* $OpenBSD: sysdep.c,v 1.13 2004/08/10 15:59:10 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "util.h"
+
+#ifdef NEED_SYSDEP_APP
+#include "app.h"
+#include "conf.h"
+#include "ipsec.h"
+
+#ifdef USE_PF_KEY_V2
+#include "pf_key_v2.h"
+#define KEY_API(x) pf_key_v2_##x
+#endif
+
+#endif /* NEED_SYSDEP_APP */
+#include "log.h"
+
+extern char *__progname;
+
+/*
+ * An as strong as possible random number generator, reverting to a
+ * deterministic pseudo-random one if regrand is set.
+ */
+u_int32_t
+sysdep_random ()
+{
+ return random();
+}
+
+/* Return the basename of the command used to invoke us. */
+char *
+sysdep_progname ()
+{
+ return __progname;
+}
+
+/* Return the length of the sockaddr struct. */
+u_int8_t
+sysdep_sa_len (struct sockaddr *sa)
+{
+ return sa->sa_len;
+}
+
+/* As regress/ use this file I protect the sysdep_app_* stuff like this. */
+#ifdef NEED_SYSDEP_APP
+/*
+ * Prepare the application we negotiate SAs for (i.e. the IPsec stack)
+ * for communication. We return a file descriptor useable to select(2) on.
+ */
+int
+sysdep_app_open ()
+{
+ return KEY_API(open) ();
+}
+
+/*
+ * When select(2) has noticed our application needs attendance, this is what
+ * gets called. FD is the file descriptor causing the alarm.
+ */
+void
+sysdep_app_handler (int fd)
+{
+ KEY_API (handler) (fd);
+}
+
+/* Check that the connection named NAME is active, or else make it active. */
+void
+sysdep_connection_check (char *name)
+{
+ KEY_API (connection_check) (name);
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ if (app_none)
+ {
+ *sz = IPSEC_SPI_SIZE;
+ /* XXX should be random instead I think. */
+ return strdup ("\x12\x34\x56\x78");
+ }
+ return KEY_API (get_spi) (sz, proto, src, dst, seq);
+}
+
+struct sa_kinfo *
+sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
+ struct sockaddr *dst)
+{
+ if (app_none)
+ return 0;
+ /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */
+ return 0;
+}
+
+/* Force communication on socket FD to go in the clear. */
+int
+sysdep_cleartext (int fd, int af)
+{
+ char *buf;
+ char *policy[] = { "in bypass", "out bypass", NULL };
+ char **p;
+ int ipp;
+ int opt;
+ char *msgstr;
+
+ if (app_none)
+ return 0;
+
+ switch (af)
+ {
+ case AF_INET:
+ ipp = IPPROTO_IP;
+ opt = IP_IPSEC_POLICY;
+ msgstr = "";
+ break;
+ case AF_INET6:
+ ipp = IPPROTO_IPV6;
+ opt = IPV6_IPSEC_POLICY;
+ msgstr = "V6";
+ break;
+ default:
+ log_print ("sysdep_cleartext: unsupported protocol family %d", af);
+ return -1;
+ }
+
+ /*
+ * Need to bypass system security policy, so I can send and
+ * receive key management datagrams in the clear.
+ */
+
+ for (p = policy; p && *p; p++)
+ {
+ buf = ipsec_set_policy (*p, strlen(*p));
+ if (buf == NULL)
+ {
+ log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror());
+ return -1;
+ }
+
+ if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0)
+ {
+ log_error ("sysdep_cleartext: "
+ "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) "
+ "failed", fd, msgstr, msgstr);
+ return -1;
+ }
+ free(buf);
+ }
+
+ return 0;
+}
+
+int
+sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (delete_spi) (sa, proto, incoming);
+}
+
+int
+sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (enable_sa) (sa, isakmp_sa);
+}
+
+int
+sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (group_spis) (sa, proto1, proto2, incoming);
+}
+
+int
+sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/freeswan/GNUmakefile.sysdep
new file mode 100644
index 0000000..9b9bd18
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/GNUmakefile.sysdep
@@ -0,0 +1,72 @@
+# $OpenBSD: GNUmakefile.sysdep,v 1.2 2003/06/03 14:53:11 ho Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# In order for this to work, invocations need to set FREESWAN to the
+# directory where FreeS/WAN is installed.
+
+ifndef FREESWAN
+FREESWAN= /usr/src/freeswan
+endif
+
+BINDIR= /usr/local/sbin
+# Partly good for RedHat 5.2, but man(1) does not find them so I have it
+# disabled for now.
+#MANDIR= /var/catman/cat
+#MAN5= isakmpd.conf.0
+#MAN8= isakmpd.0
+NOMAN=
+
+LIBGMP= -lgmp
+LIBDES= ${FREESWAN}/libdes/libdes.a
+LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep
+LIBSYSDEP= ${LIBSYSDEPDIR}/libsysdep.a
+
+FEATURES= tripledes blowfish cast ec aggressive debug
+
+SRCS+= klips.c
+
+LDADD+= ${LIBSYSDEP} ${LIBGMP} ${LIBDES} -ldl
+DPADD+= ${LIBSYSDEP} ${LIBGMP} ${LIBDES}
+
+CFLAGS+= -I${FREESWAN}/gmp -I${FREESWAN}/libdes \
+ -I${FREESWAN}/klips -I${FREESWAN}/lib -DUSE_OLD_SOCKADDR \
+ -I${.CURDIR}/sysdep/common -DSYMBOL_PREFIX='"_"'
+CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP
+CFLAGS+= -D'SALEN(x)=8'
+
+${LIBSYSDEP}:
+ cd ${LIBSYSDEPDIR}; \
+ ${MAKE} --no-print-directory ${MAKEFLAGS} CFLAGS="${CFLAGS}" MKDEP="${MKDEP}"
+
+ifneq ($(findstring install,$(MAKECMDGOALS)),install)
+SUBDIR+= sysdep/common/libsysdep
+# The regress/ subdir is completely broken in the linux environment
+SUBDIR:= $(filter-out regress,${SUBDIR})
+endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/freeswan/Makefile.sysdep
new file mode 100644
index 0000000..56bc6df
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/Makefile.sysdep
@@ -0,0 +1,75 @@
+# $OpenBSD: Makefile.sysdep,v 1.2 2003/06/03 14:53:11 ho Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+# In order for this to work, invocations need to set FREESWAN to the
+# directory where FreeS/WAN is installed.
+
+BINDIR= /usr/local/sbin
+# Partly good for RedHat 5.2, but man(1) does not find them so I have it
+# disabled for now.
+#MANDIR= /var/catman/cat
+#MAN5= isakmpd.conf.0
+#MAN8= isakmpd.0
+NOMAN=
+
+IPSEC_SRCS= klips.c
+
+LDADD+= ${.CURDIR}/sysdep/common/libsysdep/libsysdep.a \
+ ${FREESWAN}/gmp/libgmp.a
+DPADD+= ${.CURDIR}/sysdep/common/libsysdep/libsysdep.a \
+ ${FREESWAN}/gmp/libgmp.a
+
+CFLAGS+= ${DEBUG} -I${FREESWAN}/gmp -I${FREESWAN}/libdes \
+ -I${FREESWAN}/klips -I${FREESWAN}/lib -DUSE_OLD_SOCKADDR \
+ -I${.CURDIR}/sysdep/common
+
+#USE_LIBCRYPTO= defined
+#USE_KEYNOTE= defined
+
+.ifndef USE_LIBCRYPTO
+DESLIB= ${FREESWAN}/libdes/libdes.a
+DESLIBDEP= ${FREESWAN}/libdes/libdes.a
+.endif
+
+# This is a hack in order to make sure libsysdep is built before the
+# linkstage of isakmpd. As a side effect the link is always done even if
+# not necessary. Well, I just don't care.
+GENERATED+= sysdep-target
+sysdep-target:
+ cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS}
+
+.if make(clean)
+SUBDIR+= sysdep/common/libsysdep
+.endif
+
+# The regress/ subdir is completely broken in the linux environment
+.if !make(install)
+SUBDIR:= ${SUBDIR:Nregress}
+.endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/README b/keyexchange/isakmpd-20041012/sysdep/freeswan/README
new file mode 100644
index 0000000..3990ab3
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/README
@@ -0,0 +1,16 @@
+$OpenBSD: README,v 1.1 2003/05/14 20:49:37 ho Exp $
+
+Currently, you have to manually configure any IPsec interfaces and do the
+association betweent these and the physical ones. This is done like
+this in FreeS/WAN:
+
+ipsec tncfg --attach --virtual ipsec0 --physical eth0
+ifconfig ipsec0 A.B.C.D netmask E.F.G.H
+
+Then there is one special configuration option in the IPsec-connection
+sections for Phase 2 of the configuration file, named Next-hop, which
+should be set to the next hop's IP address along the way to the peer:
+
+Next-hop= I.J.K.L
+
+This is specific to the way FreeS/WAN works.
diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.c b/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.c
new file mode 100644
index 0000000..d362333
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.c
@@ -0,0 +1,662 @@
+/* $OpenBSD: klips.c,v 1.3 2003/09/26 15:59:34 aaron Exp $ */
+
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <asm/types.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <linux/sockios.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <freeswan.h>
+#include <net/ipsec/radij.h>
+#include <net/ipsec/ipsec_encap.h>
+#include <net/ipsec/ipsec_netlink.h>
+#include <net/ipsec/ipsec_xform.h>
+#include <net/ipsec/ipsec_ipe4.h>
+#include <net/ipsec/ipsec_ah.h>
+#include <net/ipsec/ipsec_esp.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "ipsec_num.h"
+#include "isakmp.h"
+#include "log.h"
+#include "klips.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+
+#define KLIPS_DEVICE "/dev/ipsec"
+
+#define PROC_ROUTE_FILE "/proc/net/route"
+#define PROC_ROUTE_FMT "%15s %127s %127s %X %d %d %d %127s %d %d %d\n"
+
+/* XXX Maybe these are available through some system-supplied define? */
+#define AH_NEW_XENCAP_LEN (3 * sizeof(u_short) + 2 * sizeof(u_char))
+#define ESP_NEW_XENCAP_LEN sizeof (struct espblkrply_edata)
+#define EMT_GRPSPIS_COMPLEN (sizeof (((struct encap_msghdr *)0)->em_rel[0]))
+
+/* How often should we check that connections we require to be up, are up? */
+#define KLIPS_CHECK_FREQ 60
+
+static int klips_socket;
+
+/* Open the KLIPS device. */
+int
+klips_open ()
+{
+ int fd;
+
+ fd = open (KLIPS_DEVICE, O_RDWR);
+ if (fd == -1)
+ {
+ log_error ("klips_open: open (\"%s\", O_RDWR) failed", KLIPS_DEVICE);
+ return -1;
+ }
+ klips_socket = fd;
+ return fd;
+}
+
+/* Write a KLIPS request down to the kernel. */
+static int
+klips_write (struct encap_msghdr *em)
+{
+ ssize_t n;
+
+ em->em_magic = EM_MAGIC;
+ em->em_version = 0;
+
+ LOG_DBG_BUF ((LOG_SYSDEP, 30, "klips_write: em", (u_int8_t *)em,
+ em->em_msglen));
+ n = write (klips_socket, em, em->em_msglen);
+ if (n == -1)
+ {
+ log_error ("write (%d, ...) failed", klips_socket);
+ return -1;
+ }
+ if ((size_t)n != em->em_msglen)
+ {
+ log_error ("write (%d, ...) returned prematurely", klips_socket);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+klips_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ u_int8_t *spi;
+ u_int32_t spinum;
+
+ *sz = IPSEC_SPI_SIZE;
+ spi = malloc (*sz);
+ if (!spi)
+ return 0;
+ do
+ spinum = sysdep_random ();
+ while (spinum < IPSEC_SPI_LOW);
+ spinum = htonl (spinum);
+ memcpy (spi, &spinum, *sz);
+
+ LOG_DBG_BUF ((LOG_SYSDEP, 50, "klips_get_spi: spi", spi, *sz));
+
+ return spi;
+}
+
+/* Group 2 SPIs in a chain. XXX Not fully implemented yet. */
+int
+klips_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2,
+ int incoming)
+{
+ struct encap_msghdr *emsg = 0;
+ struct sockaddr *dst;
+
+ emsg = calloc (1, EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN);
+ if (!emsg)
+ return -1;
+
+ emsg->em_msglen = EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN;
+ emsg->em_type = EMT_GRPSPIS;
+
+ /*
+ * XXX The code below is wrong if we are in tunnel mode.
+ * The fix is to reorder stuff so the IP-in-IP SA will always come
+ * upfront, and if there are two such, one is dropped.
+ */
+ memcpy (&emsg->em_rel[0].emr_spi, proto1->spi[incoming],
+ sizeof emsg->em_rel[0].emr_spi);
+ memcpy (&emsg->em_rel[1].emr_spi, proto2->spi[incoming],
+ sizeof emsg->em_rel[1].emr_spi);
+ if (incoming)
+ sa->transport->vtbl->get_src (sa->transport, &dst);
+ else
+ sa->transport->vtbl->get_dst (sa->transport, &dst);
+ emsg->em_rel[0].emr_dst
+ = emsg->em_rel[1].emr_dst = ((struct sockaddr_in *)dst)->sin_addr;
+ /* XXX What if IPCOMP etc. comes along? */
+ emsg->em_rel[0].emr_proto
+ = proto1->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+ emsg->em_rel[1].emr_proto
+ = proto2->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+
+ if (klips_write (emsg))
+ goto cleanup;
+ free (emsg);
+
+ LOG_DBG ((LOG_SYSDEP, 50, "klips_group_spis: done"));
+
+ return 0;
+
+ cleanup:
+ if (emsg)
+ free (emsg);
+ return -1;
+}
+
+/* Store/update a SPI with full information into the kernel. */
+int
+klips_set_spi (struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ struct encap_msghdr *emsg = 0;
+ struct ipsec_proto *iproto = proto->data;
+ struct sockaddr *dst, *src;
+ int keylen, hashlen;
+ size_t len;
+ struct ipe4_xdata *ip4x;
+
+ /* Actually works for all. */
+ struct espblkrply_edata *edx;
+
+ /* Actually works for all. */
+ struct ahhmacmd5_edata *amx;
+
+ switch (proto->proto)
+ {
+ case IPSEC_PROTO_IPSEC_ESP:
+ keylen = ipsec_esp_enckeylength (proto);
+ hashlen = ipsec_esp_authkeylength (proto);
+ len = EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN;
+ emsg = calloc (1, len);
+ if (!emsg)
+ return -1;
+
+ emsg->em_proto = IPPROTO_ESP;
+
+ edx = (struct espblkrply_edata *)emsg->em_dat;
+
+ /* Funny expression due to I just want one switch. */
+ switch (proto->id | (iproto->auth << 8))
+ {
+ case IPSEC_ESP_3DES:
+ emsg->em_alg = XF_ESP3DES;
+ break;
+
+ case IPSEC_ESP_3DES | (IPSEC_AUTH_HMAC_MD5 << 8):
+ emsg->em_alg = XF_ESP3DESMD596;
+ break;
+
+ case IPSEC_ESP_3DES | (IPSEC_AUTH_HMAC_SHA << 8):
+ emsg->em_alg = XF_ESP3DESSHA196;
+ break;
+
+ default:
+ LOG_DBG ((LOG_SYSDEP, 10,
+ "klips_set_spi: Unsupported enc/auth alg negotiated"));
+ return -1;
+ }
+
+ /* XXX What if we have a protocol requiring IV? */
+ edx->eme_ivlen = EMT_ESPDES_IV_SZ;
+ edx->eme_klen = keylen;
+ edx->ame_klen = hashlen;
+#if 0
+ /* I have reason to believe Shared-SADB won't work at all in KLIPS. */
+ edx->eme_ooowin
+ = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window;
+#else
+ edx->eme_ooowin = iproto->replay_window;
+#endif
+ /*
+ * XXX Pluto sets the unused by KLIPS flag EME_INITIATOR in
+ * edx->eme_flags, if the party is the initiator. Should we too?
+ */
+ edx->eme_flags = 0;
+ memcpy (edx->eme_key, iproto->keymat[incoming], keylen);
+ if (iproto->auth)
+ memcpy (edx->ame_key, iproto->keymat[incoming] + keylen, hashlen);
+ break;
+
+ case IPSEC_PROTO_IPSEC_AH:
+ hashlen = ipsec_ah_keylength (proto);
+ len = EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + hashlen;
+ emsg = calloc (1, len);
+ if (!emsg)
+ return -1;
+
+ emsg->em_proto = IPPROTO_AH;
+
+ amx = (struct ahhmacmd5_edata *)emsg->em_dat;
+
+ switch (proto->id)
+ {
+ case IPSEC_AH_MD5:
+ emsg->em_alg = XF_AHHMACMD5;
+ break;
+
+ case IPSEC_AH_SHA:
+ emsg->em_alg = XF_AHHMACSHA1;
+ break;
+
+ default:
+ /* XXX Log? */
+ goto cleanup;
+ }
+
+ /* XXX Should we be able to send in different lengths here? */
+ amx->ame_alen = amx->ame_klen = hashlen;
+#if 0
+ /* I have reason to believe Shared-SADB won't work at all in KLIPS. */
+ amx->ame_ooowin
+ = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window;
+#else
+ amx->ame_ooowin = iproto->replay_window;
+#endif
+ amx->ame_replayp = amx->ame_ooowin > 0;
+ memcpy (amx->ame_key, iproto->keymat[incoming], hashlen);
+ break;
+
+ default:
+ /* XXX Log? */
+ goto cleanup;
+ }
+
+ emsg->em_msglen = len;
+ emsg->em_type = EMT_SETSPI;
+ memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi);
+ emsg->em_flags = incoming ? EMT_INBOUND : 0;
+
+ /*
+ * XXX Addresses has to be thought through. Assumes IPv4.
+ */
+ sa->transport->vtbl->get_dst (sa->transport, &dst);
+ sa->transport->vtbl->get_src (sa->transport, &src);
+ emsg->em_dst
+ = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr;
+
+ /*
+ * Klips does not know about expirations, thus we need to do them inside
+ * isakmpd.
+ */
+ if (sa->seconds)
+ if (sa_setup_expirations (sa))
+ goto cleanup;
+
+ LOG_DBG ((LOG_SYSDEP, 10, "klips_set_spi: proto %d dst %s SPI 0x%x",
+ emsg->em_proto, inet_ntoa (emsg->em_dst), htonl (emsg->em_spi)));
+ if (klips_write (emsg))
+ goto cleanup;
+ free (emsg);
+
+ /* If we are tunneling we have to setup an IP in IP tunnel too. */
+ if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL)
+ {
+ len = EMT_SETSPI_FLEN + EMT_IPE4_ULEN;
+ emsg = calloc (1, len);
+ if (!emsg)
+ goto cleanup;
+
+ emsg->em_proto = IPPROTO_IPIP;
+ emsg->em_msglen = len;
+ emsg->em_type = EMT_SETSPI;
+ /*
+ * XXX Code in Pluto suggests this is not possible, but that we have
+ * to have a unique SPI for the IP4 SA.
+ */
+ memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi);
+ emsg->em_flags = 0;
+ emsg->em_alg = XF_IP4;
+
+ ip4x = (struct ipe4_xdata *)emsg->em_dat;
+ ip4x->i4_dst = emsg->em_dst
+ = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr;
+ ip4x->i4_src
+ = ((struct sockaddr_in *)(incoming ? dst : src))->sin_addr;
+
+ LOG_DBG ((LOG_SYSDEP, 10, "klips_set_spi: proto %d dst %s SPI 0x%x",
+ emsg->em_proto, inet_ntoa (emsg->em_dst),
+ htonl (emsg->em_spi)));
+ if (klips_write (emsg))
+ goto cleanup;
+ free (emsg);
+
+ /*
+ * Grouping the IP-in-IP SA with the IPsec one means we must be careful
+ * in klips_group_spis so that we'll remove duplicate IP-in-IP SAs
+ * and get everything grouped in the right order.
+ *
+ * XXX Could we not share code with klips_group_spis here?
+ */
+ emsg = calloc (1, EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN);
+ if (!emsg)
+ goto cleanup;
+
+ emsg->em_msglen = EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN;
+ emsg->em_type = EMT_GRPSPIS;
+
+ memcpy (&emsg->em_rel[0].emr_spi, proto->spi[incoming],
+ sizeof emsg->em_rel[0].emr_spi);
+ memcpy (&emsg->em_rel[1].emr_spi, proto->spi[incoming],
+ sizeof emsg->em_rel[1].emr_spi);
+ emsg->em_rel[0].emr_dst = emsg->em_rel[1].emr_dst
+ = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr;
+
+ emsg->em_rel[0].emr_proto = IPPROTO_IPIP;
+ /* XXX What if IPCOMP etc. comes along? */
+ emsg->em_rel[1].emr_proto
+ = proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+
+ if (klips_write (emsg))
+ goto cleanup;
+ free (emsg);
+ }
+
+ LOG_DBG ((LOG_SYSDEP, 50, "klips_set_spi: done"));
+
+ return 0;
+
+ cleanup:
+ /* XXX Cleanup the potential SAs we have setup. */
+ if (emsg)
+ free (emsg);
+ return -1;
+}
+
+/*
+ * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO
+ * of the IKE security association SA.
+ */
+int
+klips_delete_spi (struct sa *sa, struct proto *proto, int incoming)
+{
+ struct encap_msghdr *emsg = 0;
+ struct sockaddr *dst;
+ struct ipsec_proto *iproto = proto->data;
+
+ emsg = calloc (1, EMT_SETSPI_FLEN);
+ if (!emsg)
+ return -1;
+
+ emsg->em_msglen = EMT_SETSPI_FLEN;
+ emsg->em_type = EMT_DELSPI;
+
+ memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi);
+ if (incoming)
+ sa->transport->vtbl->get_src (sa->transport, &dst);
+ else
+ sa->transport->vtbl->get_dst (sa->transport, &dst);
+ emsg->em_dst = ((struct sockaddr_in *)dst)->sin_addr;
+ /* XXX What if IPCOMP etc. comes along? */
+ emsg->em_proto
+ = (iproto->encap_mode == IPSEC_ENCAP_TUNNEL ? IPPROTO_IPIP
+ : proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH);
+
+ if (klips_write (emsg))
+ goto cleanup;
+ free (emsg);
+
+ LOG_DBG ((LOG_SYSDEP, 50, "klips_delete_spi: done"));
+
+ return 0;
+
+ cleanup:
+ if (emsg)
+ free (emsg);
+ return -1;
+}
+
+int
+klips_hex_decode (char *src, u_char *dst, int dstsize)
+{
+ char *p, *pe;
+ u_char *q, *qe, ch, cl;
+
+ pe = src + strlen (src);
+ qe = dst + dstsize;
+
+ for (p = src, q = dst; p < pe && q < qe && isxdigit ((int)*p); p += 2)
+ {
+ ch = tolower (p[0]);
+ cl = tolower (p[1]);
+
+ if ((ch >= '0') && (ch <= '9'))
+ ch -= '0';
+ else if ((ch >= 'a') && (ch <= 'f'))
+ ch -= 'a' - 10;
+ else
+ return -1;
+
+ if ((cl >= '0') && (cl <= '9'))
+ cl -= '0';
+ else if ((cl >= 'a') && (cl <= 'f'))
+ cl -= 'a' - 10;
+ else
+ return -1;
+
+ *q++ = (ch << 4) | cl;
+ }
+
+ return (int)(q - dst);
+}
+
+/* Consult kernel routing table for next-hop lookup. From dugsong@monkey.org */
+u_long
+klips_route_get (u_long dst)
+{
+ FILE *f;
+ char buf[BUFSIZ];
+ char ifbuf[16], netbuf[128], gatebuf[128], maskbuf[128];
+ int i, iflags, refcnt, use, metric, mss, win, irtt;
+ u_long ret, gate, net, mask;
+
+ if ((f = fopen (PROC_ROUTE_FILE, "r")) == NULL)
+ return dst;
+
+ ret = dst;
+
+ while (fgets (buf, sizeof buf, f) != NULL)
+ {
+ i = sscanf (buf, PROC_ROUTE_FMT, ifbuf, netbuf, gatebuf, &iflags,
+ &refcnt, &use, &metric, maskbuf, &mss, &win, &irtt);
+ if (i < 10 || !(iflags & RTF_UP))
+ continue;
+
+ klips_hex_decode (netbuf, (u_char *)&net, sizeof net);
+ klips_hex_decode (gatebuf, (u_char *)&gate, sizeof gate);
+ klips_hex_decode (maskbuf, (u_char *)&mask, sizeof mask);
+
+ net = htonl (net);
+ gate = htonl (gate);
+ mask = htonl (mask);
+
+ if ((dst & mask) == net)
+ {
+ if (gate != INADDR_ANY)
+ ret = gate;
+ break;
+ }
+ }
+
+ fclose (f);
+ return ret;
+}
+
+/* Enable a flow given a SA. */
+int
+klips_enable_sa (struct sa *sa, struct sa *isakmp_sa)
+{
+ struct ipsec_sa *isa = sa->data;
+ struct sockaddr *dst;
+ struct proto *proto = TAILQ_FIRST (&sa->protos);
+ struct ipsec_proto *iproto = proto->data;
+ struct encap_msghdr emsg;
+ int s = -1;
+ struct rtentry rt;
+
+ sa->transport->vtbl->get_dst (sa->transport, &dst);
+
+ /* XXX Is this needed? */
+ memset (&emsg, '\0', sizeof emsg);
+
+ emsg.em_msglen = sizeof emsg;
+ emsg.em_type = EMT_RPLACEROUTE;
+
+ memcpy (&emsg.em_erspi, proto->spi[0], sizeof emsg.em_erspi);
+ emsg.em_erdst = ((struct sockaddr_in *)dst)->sin_addr;
+
+ LOG_DBG ((LOG_SYSDEP, 50, "klips_enable_sa: src %x %x dst %x %x",
+ ntohl (isa->src_net), ntohl (isa->src_mask), ntohl (isa->dst_net),
+ ntohl (isa->dst_mask)));
+
+ /* XXX Magic constant from Pluto (26 = AF_ISDN in BSD). */
+ emsg.em_eaddr.sen_family = emsg.em_emask.sen_family = 26;
+ emsg.em_eaddr.sen_type = SENT_IP4;
+ /* XXX Magic constant from Pluto. */
+ emsg.em_emask.sen_type = 255;
+ emsg.em_eaddr.sen_len = emsg.em_emask.sen_len
+ = sizeof (struct sockaddr_encap);
+
+ emsg.em_eaddr.sen_ip_src.s_addr = isa->src_net;
+ emsg.em_emask.sen_ip_src.s_addr = isa->src_mask;
+ emsg.em_eaddr.sen_ip_dst.s_addr = isa->dst_net;
+ emsg.em_emask.sen_ip_dst.s_addr = isa->dst_mask;
+
+ /* XXX What if IPCOMP etc. comes along? */
+ emsg.em_erproto
+ = (iproto->encap_mode == IPSEC_ENCAP_TUNNEL ? IPPROTO_IPIP
+ : proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH);
+
+ if (klips_write (&emsg))
+ {
+ emsg.em_type = EMT_SETEROUTE;
+ if (klips_write (&emsg))
+ goto cleanup;
+ }
+
+ s = socket (PF_INET, SOCK_DGRAM, AF_UNSPEC);
+ if (s == -1)
+ {
+ log_error ("klips_enable_sa: "
+ "socket(PF_INET, SOCK_DGRAM, AF_UNSPEC) failed");
+ goto cleanup;
+ }
+
+ memset (&rt, '\0', sizeof rt);
+ rt.rt_dst.sa_family = AF_INET;
+ ((struct sockaddr_in *)&rt.rt_dst)->sin_addr.s_addr = isa->dst_net;
+ rt.rt_genmask.sa_family = AF_INET;
+ ((struct sockaddr_in *)&rt.rt_genmask)->sin_addr.s_addr = isa->dst_mask;
+ rt.rt_gateway.sa_family = AF_INET;
+
+ ((struct sockaddr_in *)&rt.rt_gateway)->sin_addr.s_addr
+ = klips_route_get (emsg.em_erdst.s_addr);
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ /* XXX What if we have multiple interfaces? */
+ rt.rt_dev = "ipsec0";
+
+ if (ioctl (s, SIOCDELRT, &rt) == -1 && errno != ESRCH)
+ {
+ log_error ("klips_enable_sa: ioctl (%d, SIOCDELRT, %p) failed", s, &rt);
+ goto cleanup;
+ }
+
+ if (ioctl (s, SIOCADDRT, &rt) == -1)
+ {
+ log_error ("klips_enable_sa: ioctl (%d, SIOCADDRT, %p) failed", s, &rt);
+ goto cleanup;
+ }
+
+ close (s);
+ return 0;
+
+ cleanup:
+ if (s != -1)
+ close (s);
+ return -1;
+}
+
+static void
+klips_stayalive (struct exchange *exchange, void *vconn, int fail)
+{
+ char *conn = vconn;
+ struct sa *sa;
+
+ /* XXX What if it is phase 1? */
+ sa = sa_lookup_by_name (conn, 2);
+ if (sa)
+ sa->flags |= SA_FLAG_STAYALIVE;
+}
+
+/* Establish the connection in VCONN and set the stayalive flag for it. */
+void
+klips_connection_check (char *conn)
+{
+ if (!sa_lookup_by_name (conn, 2))
+ {
+ LOG_DBG ((LOG_SYSDEP, 70, "klips_connection_check: SA for %s missing",
+ conn));
+ exchange_establish (conn, klips_stayalive, conn);
+ }
+ else
+ LOG_DBG ((LOG_SYSDEP, 70, "klips_connection_check: SA for %s exists",
+ conn));
+}
diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.h b/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.h
new file mode 100644
index 0000000..a786dcb
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: klips.h,v 1.2 2003/06/03 14:53:11 ho Exp $ */
+
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _KLIPS_H_
+#define _KLIPS_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+struct proto;
+struct sa;
+struct sockaddr;
+
+extern void klips_connection_check (char *);
+extern int klips_delete_spi (struct sa *, struct proto *, int);
+extern int klips_enable_sa (struct sa *, struct sa *);
+extern u_int8_t *klips_get_spi (size_t *, u_int8_t, struct sockaddr *, int,
+ struct sockaddr *, int, u_int32_t);
+extern int klips_group_spis (struct sa *, struct proto *, struct proto *,
+ int);
+extern int klips_open (void);
+extern int klips_set_spi (struct sa *, struct proto *, int);
+
+#endif /* _KLIPS_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/sys/queue.h b/keyexchange/isakmpd-20041012/sysdep/freeswan/sys/queue.h
new file mode 100644
index 0000000..ae555ee
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/sys/queue.h
@@ -0,0 +1,333 @@
+/* $OpenBSD: queue.h,v 1.2 2003/06/02 20:06:15 millert Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 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. 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.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+/*
+ * This file defines four types of data structures: lists, simple queues,
+ * tail queues, and circular queues.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so only elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+#define LIST_END(head) NULL
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ (head)->lh_first = NULL; \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \
+ if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_END(head) NULL
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = (void *)(head); \
+ (head)->cqh_last = (void *)(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == (void *)(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == (void *)(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = (void *)(head); \
+ if ((head)->cqh_last == (void *)(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = (void *)(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == (void *)(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == (void *)(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == (void *)(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+} while (0)
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep-os.h
new file mode 100644
index 0000000..72e9d08
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep-os.h
@@ -0,0 +1,46 @@
+/* $OpenBSD: sysdep-os.h,v 1.2 2003/06/03 14:53:11 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _SYSDEP_OS_H_
+#define _SYSDEP_OS_H_
+
+typedef u_int16_t in_port_t;
+typedef u_int32_t in_addr_t;
+
+#if 0
+/*
+ * Why -D__USE_GNU does not work in order to get this from stdio.h beats me.
+ */
+extern int asprintf(char **, const char *, ...);
+#endif
+
+#define DL_LAZY RTLD_LAZY
+
+#endif /* _SYSDEP_OS_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep.c
new file mode 100644
index 0000000..9e99d7e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep.c
@@ -0,0 +1,186 @@
+/* $OpenBSD: sysdep.c,v 1.3 2004/08/10 15:59:10 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <md5.h>
+#include <unistd.h>
+
+#include "sysdep.h"
+
+#ifdef NEED_SYSDEP_APP
+#include "app.h"
+#include "conf.h"
+#include "ipsec.h"
+#include "klips.h"
+#endif /* NEED_SYSDEP_APP */
+#include "log.h"
+#include "sysdep.h"
+
+extern char *__progname;
+
+u_int32_t
+sysdep_random ()
+{
+ u_int32_t rndval;
+ u_char sig[16];
+ MD5_CTX ctx;
+ int fd, i;
+ struct {
+ struct timeval tv;
+ u_int rnd[(128 - sizeof (struct timeval)) / sizeof (u_int)];
+ } rdat;
+
+ fd = open ("/dev/urandom", O_RDONLY);
+ if (fd != -1)
+ {
+ read (fd, rdat.rnd, sizeof(rdat.rnd));
+ close (fd);
+ }
+ MD5Init (&ctx);
+ MD5Update (&ctx, (char *)&rdat, sizeof(rdat));
+ MD5Final (sig, &ctx);
+
+ rndval = 0;
+ for (i = 0; i < 4; i++)
+ {
+ u_int32_t *tmp = (u_int32_t *)&sig[i * 4];
+ rndval ^= *tmp;
+ }
+
+ return rndval;
+}
+
+char *
+sysdep_progname ()
+{
+ return __progname;
+}
+
+/* Return the length of the sockaddr struct. */
+u_int8_t
+sysdep_sa_len (struct sockaddr *sa)
+{
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ return sizeof (struct sockaddr_in);
+ case AF_INET6:
+ return sizeof (struct sockaddr_in6);
+ }
+ log_print ("sysdep_sa_len: unknown sa family %d", sa->sa_family);
+ return sizeof (struct sockaddr_in);
+}
+
+/* As regress/ use this file I protect the sysdep_app_* stuff like this. */
+#ifdef NEED_SYSDEP_APP
+int
+sysdep_app_open ()
+{
+ return klips_open ();
+}
+
+void
+sysdep_app_handler (int fd)
+{
+}
+
+/* Check that the connection named NAME is active, or else make it active. */
+void
+sysdep_connection_check (char *name)
+{
+ klips_connection_check (name);
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ if (app_none)
+ {
+ *sz = IPSEC_SPI_SIZE;
+ /* XXX should be random instead I think. */
+ return strdup ("\x12\x34\x56\x78");
+ }
+
+ return klips_get_spi (sz, proto, src, dst, seq);
+}
+
+struct sa_kinfo *
+sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
+ struct sockaddr *dst)
+{
+ if (app_none)
+ return 0;
+ /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */
+ return 0;
+}
+
+int
+sysdep_cleartext (int fd, int af)
+{
+ return 0;
+}
+
+int
+sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming)
+{
+ return klips_delete_spi (sa, proto, incoming);
+}
+
+int
+sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa)
+{
+ return klips_enable_sa (sa, isakmp_sa);
+}
+
+int
+sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int incoming)
+{
+ return klips_group_spis (sa, proto1, proto2, incoming);
+}
+
+int
+sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ return klips_set_spi (sa, proto, incoming, isakmp_sa);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/linux/GNUmakefile.sysdep
new file mode 100644
index 0000000..6c0fa10
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/linux/GNUmakefile.sysdep
@@ -0,0 +1,60 @@
+# $OpenBSD: GNUmakefile.sysdep,v 1.9 2004/08/10 09:49:51 ho Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
+# Copyright (c) 2003 Thomas Walpuski. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+LIBGMP:= /usr/lib/libgmp.a
+LIBCRYPTO:= /usr/lib/libcrypto.a
+LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep
+LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a
+
+LDADD+= -lgmp ${LIBSYSDEP} ${LIBCRYPTO}
+DPADD+= ${LIBGMP} ${LIBSYSDEP}
+
+CFLAGS+= -DHAVE_GETNAMEINFO -DUSE_OLD_SOCKADDR -DHAVE_PCAP \
+ -DNEED_SYSDEP_APP -DMP_FLAVOUR=MP_FLAVOUR_GMP -DUSE_AES \
+ -I${.CURDIR}/sysdep/linux/include -I${.CURDIR}/sysdep/common \
+ -I/usr/include/openssl
+
+FEATURES= debug tripledes blowfish cast ec aggressive x509 policy
+FEATURES+= dpd nat_traversal isakmp_cfg des aes
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPO= defined
+HAVE_DLOPEN= defined
+USE_KEYNOTE= defined
+
+# hack libsysdep.a dependenc
+${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}:
+ cd ${LIBSYSDEPDIR} && \
+ ${MAKE} --no-print-directory \
+ CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS}
+
+ifeq ($(findstring clean,$(MAKECMDGOALS)),clean)
+SUBDIR+= sysdep/common/libsysdep
+MAKEFLAGS+= --no-print-directory
+endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/bitstring.h b/keyexchange/isakmpd-20041012/sysdep/linux/bitstring.h
new file mode 100644
index 0000000..ce20dd9
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/linux/bitstring.h
@@ -0,0 +1,128 @@
+/* $OpenBSD: bitstring.h,v 1.1 2003/09/02 18:11:15 ho Exp $ */
+/* $NetBSD: bitstring.h,v 1.5 1997/05/14 15:49:55 pk Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Vixie.
+ *
+ * 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. 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.
+ *
+ * @(#)bitstring.h 8.1 (Berkeley) 7/19/93
+ */
+
+#ifndef _BITSTRING_H_
+#define _BITSTRING_H_
+
+/* modified for SV/AT and bitstring bugfix by M.R.Murphy, 11oct91
+ * bitstr_size changed gratuitously, but shorter
+ * bit_alloc spelling error fixed
+ * the following were efficient, but didn't work, they've been made to
+ * work, but are no longer as efficient :-)
+ * bit_nclear, bit_nset, bit_ffc, bit_ffs
+ */
+typedef unsigned char bitstr_t;
+
+/* internal macros */
+ /* byte of the bitstring bit is in */
+#define _bit_byte(bit) \
+ ((bit) >> 3)
+
+ /* mask for the bit within its byte */
+#define _bit_mask(bit) \
+ (1 << ((bit)&0x7))
+
+/* external macros */
+ /* bytes in a bitstring of nbits bits */
+#define bitstr_size(nbits) \
+ (((nbits) + 7) >> 3)
+
+ /* allocate a bitstring */
+#define bit_alloc(nbits) \
+ (bitstr_t *)calloc((size_t)bitstr_size(nbits), sizeof(bitstr_t))
+
+ /* allocate a bitstring on the stack */
+#define bit_decl(name, nbits) \
+ ((name)[bitstr_size(nbits)])
+
+ /* is bit N of bitstring name set? */
+#define bit_test(name, bit) \
+ ((name)[_bit_byte(bit)] & _bit_mask(bit))
+
+ /* set bit N of bitstring name */
+#define bit_set(name, bit) \
+ ((name)[_bit_byte(bit)] |= _bit_mask(bit))
+
+ /* clear bit N of bitstring name */
+#define bit_clear(name, bit) \
+ ((name)[_bit_byte(bit)] &= ~_bit_mask(bit))
+
+ /* clear bits start ... stop in bitstring */
+#define bit_nclear(name, start, stop) do { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ while (_start <= _stop) { \
+ bit_clear(_name, _start); \
+ _start++; \
+ } \
+} while(0)
+
+ /* set bits start ... stop in bitstring */
+#define bit_nset(name, start, stop) do { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ while (_start <= _stop) { \
+ bit_set(_name, _start); \
+ _start++; \
+ } \
+} while(0)
+
+ /* find first bit clear in name */
+#define bit_ffc(name, nbits, value) do { \
+ register bitstr_t *_name = name; \
+ register int _bit, _nbits = nbits, _value = -1; \
+ for (_bit = 0; _bit < _nbits; ++_bit) \
+ if (!bit_test(_name, _bit)) { \
+ _value = _bit; \
+ break; \
+ } \
+ *(value) = _value; \
+} while(0)
+
+ /* find first bit set in name */
+#define bit_ffs(name, nbits, value) do { \
+ register bitstr_t *_name = name; \
+ register int _bit, _nbits = nbits, _value = -1; \
+ for (_bit = 0; _bit < _nbits; ++_bit) \
+ if (bit_test(_name, _bit)) { \
+ _value = _bit; \
+ break; \
+ } \
+ *(value) = _value; \
+} while(0)
+
+#endif /* !_BITSTRING_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/include/bitstring.h b/keyexchange/isakmpd-20041012/sysdep/linux/include/bitstring.h
new file mode 100644
index 0000000..1939615
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/linux/include/bitstring.h
@@ -0,0 +1,132 @@
+/* $OpenBSD: bitstring.h,v 1.4 2002/06/19 02:50:10 millert Exp $ */
+/* $NetBSD: bitstring.h,v 1.5 1997/05/14 15:49:55 pk Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Vixie.
+ *
+ * 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.
+ *
+ * @(#)bitstring.h 8.1 (Berkeley) 7/19/93
+ */
+
+#ifndef _BITSTRING_H_
+#define _BITSTRING_H_
+
+/* modified for SV/AT and bitstring bugfix by M.R.Murphy, 11oct91
+ * bitstr_size changed gratuitously, but shorter
+ * bit_alloc spelling error fixed
+ * the following were efficient, but didn't work, they've been made to
+ * work, but are no longer as efficient :-)
+ * bit_nclear, bit_nset, bit_ffc, bit_ffs
+ */
+typedef unsigned char bitstr_t;
+
+/* internal macros */
+ /* byte of the bitstring bit is in */
+#define _bit_byte(bit) \
+ ((bit) >> 3)
+
+ /* mask for the bit within its byte */
+#define _bit_mask(bit) \
+ (1 << ((bit)&0x7))
+
+/* external macros */
+ /* bytes in a bitstring of nbits bits */
+#define bitstr_size(nbits) \
+ (((nbits) + 7) >> 3)
+
+ /* allocate a bitstring */
+#define bit_alloc(nbits) \
+ (bitstr_t *)calloc((size_t)bitstr_size(nbits), sizeof(bitstr_t))
+
+ /* allocate a bitstring on the stack */
+#define bit_decl(name, nbits) \
+ ((name)[bitstr_size(nbits)])
+
+ /* is bit N of bitstring name set? */
+#define bit_test(name, bit) \
+ ((name)[_bit_byte(bit)] & _bit_mask(bit))
+
+ /* set bit N of bitstring name */
+#define bit_set(name, bit) \
+ ((name)[_bit_byte(bit)] |= _bit_mask(bit))
+
+ /* clear bit N of bitstring name */
+#define bit_clear(name, bit) \
+ ((name)[_bit_byte(bit)] &= ~_bit_mask(bit))
+
+ /* clear bits start ... stop in bitstring */
+#define bit_nclear(name, start, stop) do { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ while (_start <= _stop) { \
+ bit_clear(_name, _start); \
+ _start++; \
+ } \
+} while(0)
+
+ /* set bits start ... stop in bitstring */
+#define bit_nset(name, start, stop) do { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ while (_start <= _stop) { \
+ bit_set(_name, _start); \
+ _start++; \
+ } \
+} while(0)
+
+ /* find first bit clear in name */
+#define bit_ffc(name, nbits, value) do { \
+ register bitstr_t *_name = name; \
+ register int _bit, _nbits = nbits, _value = -1; \
+ for (_bit = 0; _bit < _nbits; ++_bit) \
+ if (!bit_test(_name, _bit)) { \
+ _value = _bit; \
+ break; \
+ } \
+ *(value) = _value; \
+} while(0)
+
+ /* find first bit set in name */
+#define bit_ffs(name, nbits, value) do { \
+ register bitstr_t *_name = name; \
+ register int _bit, _nbits = nbits, _value = -1; \
+ for (_bit = 0; _bit < _nbits; ++_bit) \
+ if (bit_test(_name, _bit)) { \
+ _value = _bit; \
+ break; \
+ } \
+ *(value) = _value; \
+} while(0)
+
+#endif /* !_BITSTRING_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/include/sys/queue.h b/keyexchange/isakmpd-20041012/sysdep/linux/include/sys/queue.h
new file mode 100644
index 0000000..c4ac33d
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/linux/include/sys/queue.h
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 1991, 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.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ * $FreeBSD: src/sys/sys/queue.h,v 1.45 2001/12/11 11:49:58 sheldonh Exp $
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+//#include <machine/ansi.h> /* for __offsetof */
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ * SLIST LIST STAILQ TAILQ
+ * _HEAD + + + +
+ * _HEAD_INITIALIZER + + + +
+ * _ENTRY + + + +
+ * _INIT + + + +
+ * _EMPTY + + + +
+ * _FIRST + + + +
+ * _NEXT + + + +
+ * _PREV - - - +
+ * _LAST - - + +
+ * _FOREACH + + + +
+ * _FOREACH_REVERSE - - - +
+ * _INSERT_HEAD + + + +
+ * _INSERT_BEFORE - + - +
+ * _INSERT_AFTER + + + +
+ * _INSERT_TAIL - - + +
+ * _REMOVE_HEAD + - + -
+ * _REMOVE + + + +
+ *
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head) ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var); \
+ (var) = SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do { \
+ SLIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+ SLIST_NEXT((slistelm), field) = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
+ SLIST_FIRST((head)) = (elm); \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if (SLIST_FIRST((head)) == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = SLIST_FIRST((head)); \
+ while (SLIST_NEXT(curelm, field) != (elm)) \
+ curelm = SLIST_NEXT(curelm, field); \
+ SLIST_NEXT(curelm, field) = \
+ SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
+ } \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first;/* first element */ \
+ struct type **stqh_last;/* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+struct { \
+ struct type *stqe_next; /* next element */ \
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for((var) = STAILQ_FIRST((head)); \
+ (var); \
+ (var) = STAILQ_NEXT((var), field))
+
+#define STAILQ_INIT(head) do { \
+ STAILQ_FIRST((head)) = NULL; \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_NEXT((tqelm), field) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_FIRST((head)) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
+ STAILQ_NEXT((elm), field) = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY(head) ? \
+ NULL : \
+ ((struct type *) \
+ ((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE(head, elm, type, field) do { \
+ if (STAILQ_FIRST((head)) == (elm)) { \
+ STAILQ_REMOVE_HEAD(head, field); \
+ } \
+ else { \
+ struct type *curelm = STAILQ_FIRST((head)); \
+ while (STAILQ_NEXT(curelm, field) != (elm)) \
+ curelm = STAILQ_NEXT(curelm, field); \
+ if ((STAILQ_NEXT(curelm, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+ } \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do { \
+ if ((STAILQ_FIRST((head)) = \
+ STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \
+ if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head) ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = LIST_FIRST((head)); \
+ (var); \
+ (var) = LIST_NEXT((var), field))
+
+#define LIST_INIT(head) do { \
+ LIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+ LIST_NEXT((listelm), field)->field.le_prev = \
+ &LIST_NEXT((elm), field); \
+ LIST_NEXT((listelm), field) = (elm); \
+ (elm)->field.le_prev = &LIST_NEXT((listelm), field); \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ LIST_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &LIST_NEXT((elm), field); \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
+ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+ LIST_FIRST((head)) = (elm); \
+ (elm)->field.le_prev = &LIST_FIRST((head)); \
+} while (0)
+
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_REMOVE(elm, field) do { \
+ if (LIST_NEXT((elm), field) != NULL) \
+ LIST_NEXT((elm), field)->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = LIST_NEXT((elm), field); \
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var); \
+ (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_INIT(head) do { \
+ TAILQ_FIRST((head)) = NULL; \
+ (head)->tqh_last = &TAILQ_FIRST((head)); \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_NEXT((listelm), field) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ TAILQ_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
+ TAILQ_FIRST((head))->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_FIRST((head)) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ TAILQ_NEXT((elm), field) = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+} while (0)
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field)) != NULL) \
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
+} while (0)
+
+
+#ifdef _KERNEL
+
+/*
+ * XXX insque() and remque() are an old way of handling certain queues.
+ * They bogusly assumes that all queue heads look alike.
+ */
+
+struct quehead {
+ struct quehead *qh_link;
+ struct quehead *qh_rlink;
+};
+
+#ifdef __GNUC__
+
+static __inline void
+insque(void *a, void *b)
+{
+ struct quehead *element = (struct quehead *)a,
+ *head = (struct quehead *)b;
+
+ element->qh_link = head->qh_link;
+ element->qh_rlink = head;
+ head->qh_link = element;
+ element->qh_link->qh_rlink = element;
+}
+
+static __inline void
+remque(void *a)
+{
+ struct quehead *element = (struct quehead *)a;
+
+ element->qh_link->qh_rlink = element->qh_rlink;
+ element->qh_rlink->qh_link = element->qh_link;
+ element->qh_rlink = 0;
+}
+
+#else /* !__GNUC__ */
+
+void insque __P((void *a, void *b));
+void remque __P((void *a));
+
+#endif /* __GNUC__ */
+
+#endif /* _KERNEL */
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/sys/queue.h b/keyexchange/isakmpd-20041012/sysdep/linux/sys/queue.h
new file mode 100644
index 0000000..3f0be6c
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/linux/sys/queue.h
@@ -0,0 +1,499 @@
+/* $OpenBSD: queue.h,v 1.7 2004/04/08 16:08:21 henning Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 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. 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.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = (head)->slh_first; \
+ while( curelm->field.sle_next != (elm) ) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ } \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \
+ if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * tail queue access methods
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define CIRCLEQ_EMPTY(head) \
+ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for((var) = CIRCLEQ_LAST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = CIRCLEQ_END(head); \
+ (head)->cqh_last = CIRCLEQ_END(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
+ if ((head)->cqh_last == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_last = (elm2); \
+ else \
+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_first = (elm2); \
+ else \
+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/linux/sysdep-os.h
new file mode 100644
index 0000000..4bd5dfd
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/linux/sysdep-os.h
@@ -0,0 +1,64 @@
+/* $OpenBSD: sysdep-os.h,v 1.8 2003/06/03 15:20:41 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2003 Thomas Walpuski. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _SYSDEP_OS_H_
+#define _SYSDEP_OS_H_
+
+#include <netinet/in.h>
+#include <time.h>
+#include <sys/types.h>
+#include <linux/ipsec.h>
+
+#define KAME
+
+#define LINUX_IPSEC
+
+#define uh_sport source
+#define uh_dport dest
+#define uh_ulen len
+#define uh_sum check
+
+#ifndef CPI_RESERVED_MAX
+#define CPI_RESERVED_MIN 1
+#define CPI_RESERVED_MAX 255
+#define CPI_PRIVATE_MIN 61440
+#define CPI_PRIVATE_MAX 65536
+#endif
+
+#define SADB_X_EALG_AES SADB_X_EALG_AESCBC
+#define SADB_X_EALG_CAST SADB_X_EALG_CASTCBC
+#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC
+
+#define IP_IPSEC_POLICY 16
+#define IPV6_IPSEC_POLICY 34
+
+#define IPV6_VERSION 0x1
+
+size_t strlcat(char *dst, const char *src, size_t siz);
+size_t strlcpy(char *dst, const char *src, size_t siz);
+
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/linux/sysdep.c
new file mode 100644
index 0000000..fc3b362
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/linux/sysdep.c
@@ -0,0 +1,226 @@
+/* $OpenBSD: sysdep.c,v 1.16 2004/08/10 15:59:10 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2003 Thomas Walpuski. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "util.h"
+
+#ifdef NEED_SYSDEP_APP
+#include "app.h"
+#include "conf.h"
+#include "ipsec.h"
+#include <linux/pfkeyv2.h>
+#include <linux/ipsec.h>
+
+#ifdef USE_PF_KEY_V2
+#include "pf_key_v2.h"
+#define KEY_API(x) pf_key_v2_##x
+#endif
+
+#endif /* NEED_SYSDEP_APP */
+#include "log.h"
+
+extern char *__progname;
+
+/*
+ * An as strong as possible random number generator, reverting to a
+ * deterministic pseudo-random one if regrand is set.
+ */
+u_int32_t
+sysdep_random ()
+{
+ return arc4random();
+}
+
+/* Return the basename of the command used to invoke us. */
+char *
+sysdep_progname ()
+{
+ return __progname;
+}
+
+/* Return the length of the sockaddr struct. */
+u_int8_t
+sysdep_sa_len (struct sockaddr *sa)
+{
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ return sizeof (struct sockaddr_in);
+ case AF_INET6:
+ return sizeof (struct sockaddr_in6);
+ default:
+ log_print ("sysdep_sa_len: unknown sa family %d", sa->sa_family);
+ }
+ return sizeof (struct sockaddr_in);
+}
+
+/* As regress/ use this file I protect the sysdep_app_* stuff like this. */
+#ifdef NEED_SYSDEP_APP
+/*
+ * Prepare the application we negotiate SAs for (i.e. the IPsec stack)
+ * for communication. We return a file descriptor useable to select(2) on.
+ */
+int
+sysdep_app_open ()
+{
+ return KEY_API(open) ();
+}
+
+/*
+ * When select(2) has noticed our application needs attendance, this is what
+ * gets called. FD is the file descriptor causing the alarm.
+ */
+void
+sysdep_app_handler (int fd)
+{
+ KEY_API (handler) (fd);
+}
+
+/* Check that the connection named NAME is active, or else make it active. */
+void
+sysdep_connection_check (char *name)
+{
+ KEY_API (connection_check) (name);
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ if (app_none)
+ {
+ *sz = IPSEC_SPI_SIZE;
+ /* XXX should be random instead I think. */
+ return strdup ("\x12\x34\x56\x78");
+ }
+ return KEY_API (get_spi) (sz, proto, src, dst, seq);
+}
+
+struct sa_kinfo *
+sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
+ struct sockaddr *dst)
+{
+ if (app_none)
+ return 0;
+ /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */
+ return 0;
+}
+
+/* Force communication on socket FD to go in the clear. */
+int
+sysdep_cleartext (int fd, int af)
+{
+ struct sadb_x_policy pol_in = {
+ SADB_UPDATE,
+ SADB_EXT_SENSITIVITY,
+ IPSEC_POLICY_BYPASS,
+ IPSEC_DIR_INBOUND,
+ 0,
+ 0,
+ 0
+ };
+ struct sadb_x_policy pol_out = {
+ SADB_UPDATE,
+ SADB_EXT_SENSITIVITY,
+ IPSEC_POLICY_BYPASS,
+ IPSEC_DIR_OUTBOUND,
+ 0,
+ 0,
+ 0
+ };
+
+ if (app_none)
+ return 0;
+
+ if (!(af == AF_INET || af == AF_INET6))
+ {
+ log_print ("sysdep_cleartext: unsupported protocol family %d", af);
+ return -1;
+ }
+
+ if (setsockopt (fd, af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6,
+ af == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY,
+ &pol_in, sizeof pol_in) < 0 ||
+ setsockopt (fd, af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6,
+ af == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY,
+ &pol_out, sizeof pol_out) < 0)
+ {
+ log_error ("sysdep_cleartext: "
+ "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) "
+ "failed", fd, af == AF_INET ? "" : "V6",
+ af == AF_INET ? "" : "V6");
+ return -1;
+ }
+ return 0;
+}
+
+int
+sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (delete_spi) (sa, proto, incoming);
+}
+
+int
+sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (enable_sa) (sa, isakmp_sa);
+}
+
+int
+sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (group_spis) (sa, proto1, proto2, incoming);
+}
+
+int
+sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/netbsd/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/netbsd/GNUmakefile.sysdep
new file mode 100644
index 0000000..e506ddc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/netbsd/GNUmakefile.sysdep
@@ -0,0 +1,63 @@
+# $OpenBSD: GNUmakefile.sysdep,v 1.8 2004/06/26 03:40:57 mcbride Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
+# Copyright (c) 2000 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+
+LIBGMP:= /usr/pkg/lib/libgmp.a
+LIBCRYPTO:= /usr/lib/libcrypto.a
+
+LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep
+LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a
+
+LDADD+= ${LIBGMP} ${LIBSYSDEP}
+DPADD+= ${LIBGMP} ${LIBSYSDEP}
+
+FEATURES= debug tripledes des blowfish cast ec aggressive x509
+# Not yet
+#FEATURES+= policy
+
+CFLAGS+= -DNO_RSA -DNO_RC5 -DNO_IDEA \
+ -I${.CURDIR}/sysdep/common -I/usr/include/openssl \
+ -I/usr/include/machine -I/usr/pkg/include
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
+
+#
+# hack libsysdep.a dependency
+#
+${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}:
+ @cd ${LIBSYSDEPDIR} && \
+ ${MAKE} --no-print-directory ${MAKEFLAGS} \
+ CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS}
+
+depend: ${LIBSYSDEPDIR}/.depend
+
+ifeq ($(findstring clean, $(MAKECMDGOALS)), clean)
+SUBDIR+= sysdep/common/libsysdep
+MAKEFLAGS+= --no-print-directory
+endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/netbsd/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/netbsd/Makefile.sysdep
new file mode 100644
index 0000000..fbc75cc
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/netbsd/Makefile.sysdep
@@ -0,0 +1,79 @@
+# $OpenBSD: Makefile.sysdep,v 1.10 2004/06/26 03:40:57 mcbride Exp $
+
+#
+# Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
+# Copyright (c) 2000 Håkan Olsson. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 INN 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.
+#
+
+# Override default features
+FEATURES= tripledes des blowfish cast ec aggressive debug x509
+FEATURES+= rawkey
+# Not yet
+#FEATURES+= policy isakmp_cfg
+
+LIBGMP= /usr/pkg/lib/libgmp.a
+LIBCRYPTO= /usr/lib/libcrypto.a
+LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep
+
+LDADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a -lipsec
+DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a ${LIBIPSEC}
+
+CFLAGS+= -DNO_RSA -DNO_IDEA -DNO_RC5 \
+ -DHAVE_GETIFADDRS \
+ -I${.CURDIR}/sysdep/common
+.if exists(/usr/pkg/include/openssl/rsa.h)
+CFLAGS+= -I/usr/pkg/include/openssl
+.elif exists(/usr/include/openssl/rsa.h)
+CFLAGS+= -I/usr/include -I/usr/include/openssl
+.endif
+# mandatory for gmp
+CFLAGS+= -I/usr/pkg/include
+LDADD+= -L/usr/pkg/lib
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
+USE_GMP= defined
+
+# This is a hack in order to make sure libsysdep is built before the
+# linkstage of isakmpd. As a side effect the link is always done even if
+# not necessary. Well, I just don't care.
+GENERATED+= sysdep-target
+sysdep-target:
+ cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS}
+
+.if make(clean) || make(cleandir)
+SUBDIR+= sysdep/common/libsysdep
+.endif
+
+# Kludge around bug in /usr/share/mk/bsd.subdir.mk
+NO_REGRESS= defined
+
+beforedepend:
+ rm -f ssl
+.if exists(/usr/pkg/include/openssl/rsa.h)
+ ln -sf /usr/pkg/include/openssl ssl
+.elif exists(/usr/include/openssl/rsa.h)
+ ln -sf /usr/include/openssl ssl
+.endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep-os.h
new file mode 100644
index 0000000..b401bb1
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep-os.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: sysdep-os.h,v 1.5 2003/08/06 11:20:00 markus Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _SYSDEP_OS_H_
+
+#define _SYSDEP_OS_H_
+
+#define KAME
+
+#include <netinet6/ipsec.h>
+
+#ifndef CPI_RESERVED_MAX
+#define CPI_RESERVED_MIN 1
+#define CPI_RESERVED_MAX 255
+#define CPI_PRIVATE_MIN 61440
+#define CPI_PRIVATE_MAX 65536
+#endif
+
+#if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC)
+#define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC
+#endif
+
+#if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC)
+#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC
+#endif
+
+#endif /* _SYSDEP_OS_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep.c
new file mode 100644
index 0000000..2720715
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep.c
@@ -0,0 +1,225 @@
+/* $OpenBSD: sysdep.c,v 1.13 2004/08/10 15:59:10 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "util.h"
+
+#ifdef NEED_SYSDEP_APP
+#include "app.h"
+#include "conf.h"
+#include "ipsec.h"
+
+#ifdef USE_PF_KEY_V2
+#include "pf_key_v2.h"
+#define KEY_API(x) pf_key_v2_##x
+#endif
+
+#endif /* NEED_SYSDEP_APP */
+#include "log.h"
+
+extern char *__progname;
+
+/*
+ * An as strong as possible random number generator, reverting to a
+ * deterministic pseudo-random one if regrand is set.
+ */
+u_int32_t
+sysdep_random ()
+{
+ return random();
+}
+
+/* Return the basename of the command used to invoke us. */
+char *
+sysdep_progname ()
+{
+ return __progname;
+}
+
+/* Return the length of the sockaddr struct. */
+u_int8_t
+sysdep_sa_len (struct sockaddr *sa)
+{
+ return sa->sa_len;
+}
+
+/* As regress/ use this file I protect the sysdep_app_* stuff like this. */
+#ifdef NEED_SYSDEP_APP
+/*
+ * Prepare the application we negotiate SAs for (i.e. the IPsec stack)
+ * for communication. We return a file descriptor useable to select(2) on.
+ */
+int
+sysdep_app_open ()
+{
+ return KEY_API(open) ();
+}
+
+/*
+ * When select(2) has noticed our application needs attendance, this is what
+ * gets called. FD is the file descriptor causing the alarm.
+ */
+void
+sysdep_app_handler (int fd)
+{
+ KEY_API (handler) (fd);
+}
+
+/* Check that the connection named NAME is active, or else make it active. */
+void
+sysdep_connection_check (char *name)
+{
+ KEY_API (connection_check) (name);
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ if (app_none)
+ {
+ *sz = IPSEC_SPI_SIZE;
+ /* XXX should be random instead I think. */
+ return strdup ("\x12\x34\x56\x78");
+ }
+ return KEY_API (get_spi) (sz, proto, src, dst, seq);
+}
+
+struct sa_kinfo *
+sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
+ struct sockaddr *dst)
+{
+ if (app_none)
+ return 0;
+ /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */
+ return 0;
+}
+
+/* Force communication on socket FD to go in the clear. */
+int
+sysdep_cleartext (int fd, int af)
+{
+ char *buf;
+ char *policy[] = { "in bypass", "out bypass", NULL };
+ char **p;
+ int ipp;
+ int opt;
+ char *msgstr;
+
+ if (app_none)
+ return 0;
+
+ switch (af)
+ {
+ case AF_INET:
+ ipp = IPPROTO_IP;
+ opt = IP_IPSEC_POLICY;
+ msgstr = "";
+ break;
+ case AF_INET6:
+ ipp = IPPROTO_IPV6;
+ opt = IPV6_IPSEC_POLICY;
+ msgstr = "V6";
+ break;
+ default:
+ log_print ("sysdep_cleartext: unsupported protocol family %d", af);
+ return -1;
+ }
+
+ /*
+ * Need to bypass system security policy, so I can send and
+ * receive key management datagrams in the clear.
+ */
+
+ for (p = policy; p && *p; p++)
+ {
+ buf = ipsec_set_policy (*p, strlen(*p));
+ if (buf == NULL)
+ {
+ log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror());
+ return -1;
+ }
+
+ if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0)
+ {
+ log_error ("sysdep_cleartext: "
+ "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) "
+ "failed", fd, msgstr, msgstr);
+ return -1;
+ }
+ free(buf);
+ }
+
+ return 0;
+}
+
+int
+sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (delete_spi) (sa, proto, incoming);
+}
+
+int
+sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (enable_sa) (sa, isakmp_sa);
+}
+
+int
+sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (group_spis) (sa, proto1, proto2, incoming);
+}
+
+int
+sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/openbsd/GNUmakefile.sysdep
new file mode 100644
index 0000000..8a46424
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/GNUmakefile.sysdep
@@ -0,0 +1,52 @@
+# $OpenBSD: GNUmakefile.sysdep,v 1.5 2004/06/26 03:40:57 mcbride Exp $
+
+#
+# Copyright (c) 1999 Håkan Olsson. All rights reserved.
+# Copyright (c) 1999, 2000 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+#
+
+
+LIBGMP:= /usr/lib/libgmp.a
+LIBCRYPTO:= /usr/lib/libcrypto.a
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+USE_LIBCRYPTO= defined
+ifneq (${MACHINE_ARCH},alpha)
+ifneq (${MACHINE_ARCH},vax)
+ifneq (${MACHINE_ARCH},m88k)
+SRCS+= keynote_compat.c
+endif
+endif
+endif
+USE_KEYNOTE= defined
+
+ifndef USE_LIBCRYPTO
+DESLIB= -ldes
+DESLIBDEP= ${LIBDES}
+endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/openbsd/Makefile.sysdep
new file mode 100644
index 0000000..86688bd
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/Makefile.sysdep
@@ -0,0 +1,52 @@
+# $OpenBSD: Makefile.sysdep,v 1.24 2004/06/26 03:40:57 mcbride Exp $
+# $EOM: Makefile.sysdep,v 1.18 2001/01/26 10:55:22 niklas Exp $
+
+#
+# Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 INN 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 code was written under funding by Ericsson Radio Systems.
+#
+
+IPSEC_SRCS= pf_key_v2.c
+IPSEC_CFLAGS= -DUSE_PF_KEY_V2
+
+CFLAGS+= -DHAVE_GETIFADDRS -DHAVE_PCAP
+CFLAGS+= -DHAVE_CLOSEFROM
+
+USE_LIBCRYPTO= defined
+
+.ifdef FEATURES
+.if ${FEATURES:Mpolicy} == "policy"
+.if ${MACHINE_ARCH} != "alpha" && ${MACHINE_ARCH} != "vax" && ${MACHINE_ARCH} != "m88k"
+POLICY+= keynote_compat.c
+.endif
+USE_KEYNOTE= defined
+.endif
+.endif
+
+.ifndef USE_LIBCRYPTO
+DESLIB= -ldes
+DESLIBDEP= ${LIBDES}
+.endif
diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/keynote_compat.c b/keyexchange/isakmpd-20041012/sysdep/openbsd/keynote_compat.c
new file mode 100644
index 0000000..a464375
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/keynote_compat.c
@@ -0,0 +1,82 @@
+/* $OpenBSD: keynote_compat.c,v 1.6 2004/04/15 18:39:30 deraadt Exp $ */
+/* $EOM: keynote_compat.c,v 1.1 2000/10/15 19:18:26 niklas Exp $ */
+
+/*
+ * Copyright (c) 2000 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+/*
+ * By mistake these functions were introduced into libkeynote without
+ * updating some kind of version preprocessor symbol we can test.
+ * Provide weak functions that can be used if the libkeynote version
+ * we link against miss them.
+ */
+
+#pragma weak kn_get_string=_kn_get_string
+#pragma weak kn_free_key=_kn_free_key
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <regex.h>
+#include <keynote.h>
+
+extern void keynote_free_key(void *, int);
+extern char *keynote_get_private_key(char *);
+
+/*
+ * Exportable front-end to keynote_get_private_key().
+ */
+char *
+_kn_get_string(char *buf)
+{
+ return keynote_get_private_key(buf);
+}
+
+/*
+ * Free a key.
+ */
+void
+_kn_free_key(struct keynote_deckey *dc)
+{
+ if (dc)
+ keynote_free_key(dc->dec_key, dc->dec_algorithm);
+}
diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep-os.h
new file mode 100644
index 0000000..05200c6
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep-os.h
@@ -0,0 +1,89 @@
+/* $OpenBSD: sysdep-os.h,v 1.6 2003/06/03 14:53:11 ho Exp $ */
+/* $EOM: sysdep-os.h,v 1.3 1999/07/08 16:48:40 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _SYSDEP_OS_H_
+#define _SYSDEP_OS_H_
+
+/*
+ * OpenBSD has at various times had non-conformant PF_KEYv2 definitions.
+ * Here we transform them into being conformant.
+ */
+
+#ifdef SADB_EXT_X_SRC_MASK
+#define SADB_X_EXT_SRC_MASK SADB_EXT_X_SRC_MASK
+#define SADB_X_EXT_DST_MASK SADB_EXT_X_DST_MASK
+#define SADB_X_EXT_PROTOCOL SADB_EXT_X_PROTOCOL
+#define SADB_X_EXT_SA2 SADB_EXT_X_SA2
+#define SADB_X_EXT_SRC_FLOW SADB_EXT_X_SRC_FLOW
+#define SADB_X_EXT_DST_FLOW SADB_EXT_X_DST_FLOW
+#define SADB_X_EXT_DST2 SADB_EXT_X_DST2
+
+#define SADB_X_SATYPE_AH_OLD SADB_SATYPE_X_AH_OLD
+#define SADB_X_SATYPE_ESP_OLD SADB_SATYPE_X_ESP_OLD
+#define SADB_X_SATYPE_IPIP SADB_SATYPE_X_IPIP
+
+#define SADB_X_AALG_RIPEMD160HMAC96 SADB_AALG_X_RIPEMD160HMAC96
+#define SADB_X_AALG_MD5 SADB_AALG_X_MD5
+#define SADB_X_AALG_SHA1 SADB_AALG_X_SHA1
+
+#define SADB_X_EALG_BLF SADB_EALG_X_BLF
+#define SADB_X_EALG_CAST SADB_EALG_X_CAST
+#define SADB_X_EALG_SKIPJACK SADB_EALG_X_SKIPJACK
+
+#define SADB_X_SAFLAGS_HALFIV SADB_SAFLAGS_X_HALFIV
+#define SADB_X_SAFLAGS_TUNNEL SADB_SAFLAGS_X_TUNNEL
+#define SADB_X_SAFLAGS_CHAINDEL SADB_SAFLAGS_X_CHAINDEL
+#define SADB_X_SAFLAGS_LOCALFLOW SADB_SAFLAGS_X_LOCALFLOW
+#define SADB_X_SAFLAGS_REPLACEFLOW SADB_SAFLAGS_X_REPLACEFLOW
+
+#endif /* SADB_EXT_X_SRC_MASK */
+
+#if defined (SADB_IDENTTYPE_MBOX) && !defined (SADB_IDENTTYPE_USERFQDN)
+#define SADB_IDENTTYPE_USERFQDN SADB_IDENTTYPE_MBOX
+#endif
+
+#ifdef FLOW_X_TYPE_USE
+#define SADB_X_FLOW_TYPE_USE FLOW_X_TYPE_USE
+#define SADB_X_FLOW_TYPE_ACQUIRE FLOW_X_TYPE_ACQUIRE
+#define SADB_X_FLOW_TYPE_REQUIRE FLOW_X_TYPE_REQUIRE
+#define SADB_X_FLOW_TYPE_BYPASS FLOW_X_TYPE_BYPASS
+#define SADB_X_FLOW_TYPE_DENY FLOW_X_TYPE_DENY
+#define SADB_X_FLOW_TYPE_DONTACQ FLOW_X_TYPE_DONTACQ
+#endif
+
+#if OPENBSD_IPSEC_API_VERSION == 1
+#define sadb_x_policy sadb_policy
+#define sadb_x_policy_len sadb_policy_len
+#define sadb_x_policy_exttype sadb_policy_exttype
+#define sadb_x_policy_seq sadb_policy_seq
+#endif
+
+#endif /* _SYSDEP_OS_H_ */
diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep.c
new file mode 100644
index 0000000..f59922f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep.c
@@ -0,0 +1,266 @@
+/* $OpenBSD: sysdep.c,v 1.28 2004/08/10 15:59:11 ho Exp $ */
+/* $EOM: sysdep.c,v 1.9 2000/12/04 04:46:35 angelos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "monitor.h"
+#include "util.h"
+
+#ifdef NEED_SYSDEP_APP
+#include "app.h"
+#include "conf.h"
+#include "ipsec.h"
+
+#ifdef USE_PF_KEY_V2
+#include "pf_key_v2.h"
+#define KEY_API(x) pf_key_v2_##x
+#endif
+
+#endif /* NEED_SYSDEP_APP */
+#include "log.h"
+
+extern char *__progname;
+
+/*
+ * An as strong as possible random number generator, reverting to a
+ * deterministic pseudo-random one if regrand is set.
+ */
+u_int32_t
+sysdep_random()
+{
+ if (!regrand)
+ return arc4random();
+ else
+ return random();
+}
+
+/* Return the basename of the command used to invoke us. */
+char *
+sysdep_progname()
+{
+ return __progname;
+}
+
+/* Return the length of the sockaddr struct. */
+u_int8_t
+sysdep_sa_len(struct sockaddr *sa)
+{
+ return sa->sa_len;
+}
+
+/* As regress/ use this file I protect the sysdep_app_* stuff like this. */
+#ifdef NEED_SYSDEP_APP
+/*
+ * Prepare the application we negotiate SAs for (i.e. the IPsec stack)
+ * for communication. We return a file descriptor useable to select(2) on.
+ */
+int
+sysdep_app_open()
+{
+#ifdef USE_PRIVSEP
+ return monitor_pf_key_v2_open();
+#else
+ return KEY_API(open)();
+#endif
+}
+
+/*
+ * When select(2) has noticed our application needs attendance, this is what
+ * gets called. FD is the file descriptor causing the alarm.
+ */
+void
+sysdep_app_handler(int fd)
+{
+ KEY_API(handler)(fd);
+}
+
+/* Check that the connection named NAME is active, or else make it active. */
+void
+sysdep_connection_check(char *name)
+{
+ KEY_API(connection_check)(name);
+}
+
+/*
+ * Generate a SPI for protocol PROTO and the source/destination pair given by
+ * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
+ */
+u_int8_t *
+sysdep_ipsec_get_spi(size_t *sz, u_int8_t proto, struct sockaddr *src,
+ struct sockaddr *dst, u_int32_t seq)
+{
+ if (app_none) {
+ *sz = IPSEC_SPI_SIZE;
+ /* XXX should be random instead I think. */
+ return (u_int8_t *)strdup("\x12\x34\x56\x78");
+ }
+ return KEY_API(get_spi)(sz, proto, src, dst, seq);
+}
+
+struct sa_kinfo *
+sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
+ struct sockaddr *dst)
+{
+ if (app_none)
+ return 0;
+ return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst);
+}
+
+/* Force communication on socket FD to go in the clear. */
+int
+sysdep_cleartext(int fd, int af)
+{
+ int level, sw;
+ struct {
+ int ip_proto; /* IP protocol */
+ int auth_level;
+ int esp_trans_level;
+ int esp_network_level;
+ int ipcomp_level;
+ } optsw[] = {
+ {
+ IPPROTO_IP,
+ IP_AUTH_LEVEL,
+ IP_ESP_TRANS_LEVEL,
+ IP_ESP_NETWORK_LEVEL,
+#ifdef IP_IPCOMP_LEVEL
+ IP_IPCOMP_LEVEL
+#else
+ 0
+#endif
+ }, {
+ IPPROTO_IPV6,
+ IPV6_AUTH_LEVEL,
+ IPV6_ESP_TRANS_LEVEL,
+ IPV6_ESP_NETWORK_LEVEL,
+#ifdef IPV6_IPCOMP_LEVEL
+ IPV6_IPCOMP_LEVEL
+#else
+ 0
+#endif
+ },
+ };
+
+ if (app_none)
+ return 0;
+
+ switch (af) {
+ case AF_INET:
+ sw = 0;
+ break;
+ case AF_INET6:
+ sw = 1;
+ break;
+ default:
+ log_print("sysdep_cleartext: unsupported protocol family %d", af);
+ return -1;
+ }
+
+ /*
+ * Need to bypass system security policy, so I can send and
+ * receive key management datagrams in the clear.
+ */
+ level = IPSEC_LEVEL_BYPASS;
+ if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].auth_level,
+ (char *) &level, sizeof level) == -1) {
+ log_error("sysdep_cleartext: "
+ "setsockopt (%d, %d, IP_AUTH_LEVEL, ...) failed", fd,
+ optsw[sw].ip_proto);
+ return -1;
+ }
+ if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].esp_trans_level,
+ (char *) &level, sizeof level) == -1) {
+ log_error("sysdep_cleartext: "
+ "setsockopt (%d, %d, IP_ESP_TRANS_LEVEL, ...) failed", fd,
+ optsw[sw].ip_proto);
+ return -1;
+ }
+ if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].esp_network_level,
+ (char *) &level, sizeof level) == -1) {
+ log_error("sysdep_cleartext: "
+ "setsockopt (%d, %d, IP_ESP_NETWORK_LEVEL, ...) failed", fd,
+ optsw[sw].ip_proto);
+ return -1;
+ }
+ if (optsw[sw].ipcomp_level &&
+ monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].ipcomp_level,
+ (char *) &level, sizeof level) == -1 &&
+ errno != ENOPROTOOPT) {
+ log_error("sysdep_cleartext: "
+ "setsockopt (%d, %d, IP_IPCOMP_LEVEL, ...) failed,", fd,
+ optsw[sw].ip_proto);
+ return -1;
+ }
+ return 0;
+}
+
+int
+sysdep_ipsec_delete_spi(struct sa *sa, struct proto *proto, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API(delete_spi)(sa, proto, incoming);
+}
+
+int
+sysdep_ipsec_enable_sa(struct sa *sa, struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API(enable_sa)(sa, isakmp_sa);
+}
+
+int
+sysdep_ipsec_group_spis(struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int incoming)
+{
+ if (app_none)
+ return 0;
+ return KEY_API(group_spis)(sa, proto1, proto2, incoming);
+}
+
+int
+sysdep_ipsec_set_spi(struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
+{
+ if (app_none)
+ return 0;
+ return KEY_API(set_spi) (sa,proto, incoming, isakmp_sa);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/timer.c b/keyexchange/isakmpd-20041012/timer.c
new file mode 100644
index 0000000..45bcc49
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/timer.c
@@ -0,0 +1,139 @@
+/* $OpenBSD: timer.c,v 1.14 2004/06/14 09:55:42 ho Exp $ */
+/* $EOM: timer.c,v 1.13 2000/02/20 19:58:42 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "log.h"
+#include "timer.h"
+
+static TAILQ_HEAD(event_list, event) events;
+
+void
+timer_init(void)
+{
+ TAILQ_INIT(&events);
+}
+
+void
+timer_next_event(struct timeval **timeout)
+{
+ struct timeval now;
+
+ if (TAILQ_FIRST(&events)) {
+ gettimeofday(&now, 0);
+ if (timercmp(&now, &TAILQ_FIRST(&events)->expiration, >=))
+ timerclear(*timeout);
+ else
+ timersub(&TAILQ_FIRST(&events)->expiration, &now,
+ *timeout);
+ } else
+ *timeout = 0;
+}
+
+void
+timer_handle_expirations(void)
+{
+ struct timeval now;
+ struct event *n;
+
+ gettimeofday(&now, 0);
+ for (n = TAILQ_FIRST(&events); n && timercmp(&now, &n->expiration, >=);
+ n = TAILQ_FIRST(&events)) {
+ LOG_DBG((LOG_TIMER, 10,
+ "timer_handle_expirations: event %s(%p)", n->name,
+ n->arg));
+ TAILQ_REMOVE(&events, n, link);
+ (*n->func)(n->arg);
+ free(n);
+ }
+}
+
+struct event *
+timer_add_event(char *name, void (*func)(void *), void *arg,
+ struct timeval *expiration)
+{
+ struct event *ev = (struct event *) malloc(sizeof *ev);
+ struct event *n;
+ struct timeval now;
+
+ if (!ev)
+ return 0;
+ ev->name = name;
+ ev->func = func;
+ ev->arg = arg;
+ gettimeofday(&now, 0);
+ memcpy(&ev->expiration, expiration, sizeof *expiration);
+ for (n = TAILQ_FIRST(&events);
+ n && timercmp(expiration, &n->expiration, >=);
+ n = TAILQ_NEXT(n, link))
+ ;
+ if (n) {
+ LOG_DBG((LOG_TIMER, 10,
+ "timer_add_event: event %s(%p) added before %s(%p), "
+ "expiration in %lds", name,
+ arg, n->name, n->arg, expiration->tv_sec - now.tv_sec));
+ TAILQ_INSERT_BEFORE(n, ev, link);
+ } else {
+ LOG_DBG((LOG_TIMER, 10, "timer_add_event: event %s(%p) added "
+ "last, expiration in %lds", name, arg,
+ expiration->tv_sec - now.tv_sec));
+ TAILQ_INSERT_TAIL(&events, ev, link);
+ }
+ return ev;
+}
+
+void
+timer_remove_event(struct event *ev)
+{
+ LOG_DBG((LOG_TIMER, 10, "timer_remove_event: removing event %s(%p)",
+ ev->name, ev->arg));
+ TAILQ_REMOVE(&events, ev, link);
+ free(ev);
+}
+
+void
+timer_report(void)
+{
+ struct event *ev;
+ struct timeval now;
+
+ gettimeofday(&now, 0);
+
+ for (ev = TAILQ_FIRST(&events); ev; ev = TAILQ_NEXT(ev, link))
+ LOG_DBG((LOG_REPORT, 0,
+ "timer_report: event %s(%p) scheduled in %d seconds",
+ (ev->name ? ev->name : "<unknown>"), ev,
+ (int) (ev->expiration.tv_sec - now.tv_sec)));
+}
diff --git a/keyexchange/isakmpd-20041012/timer.h b/keyexchange/isakmpd-20041012/timer.h
new file mode 100644
index 0000000..2e890a3
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/timer.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: timer.h,v 1.7 2004/05/23 18:17:56 hshoexer Exp $ */
+/* $EOM: timer.h,v 1.6 1999/04/11 22:35:55 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+struct event {
+ TAILQ_ENTRY(event) link;
+ char *name;
+ void (*func) (void *);
+ void *arg;
+ struct timeval expiration;
+};
+
+extern void timer_init(void);
+extern void timer_next_event(struct timeval **);
+extern void timer_handle_expirations(void);
+extern struct event *timer_add_event(char *, void (*) (void *), void *,
+ struct timeval *);
+extern void timer_remove_event(struct event *);
+extern void timer_report(void);
+
+#endif /* _TIMER_H_ */
diff --git a/keyexchange/isakmpd-20041012/transport.c b/keyexchange/isakmpd-20041012/transport.c
new file mode 100644
index 0000000..023e819
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/transport.c
@@ -0,0 +1,431 @@
+/* $OpenBSD: transport.c,v 1.30 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: transport.c,v 1.43 2000/10/10 12:36:39 provos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "exchange.h"
+#include "log.h"
+#include "message.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "virtual.h"
+
+/* If no retransmit limit is given, use this as a default. */
+#define RETRANSMIT_DEFAULT 10
+
+LIST_HEAD(transport_list, transport) transport_list;
+LIST_HEAD(transport_method_list, transport_vtbl) transport_method_list;
+
+/* Call the reinit function of the various transports. */
+void
+transport_reinit(void)
+{
+ struct transport_vtbl *method;
+
+ for (method = LIST_FIRST(&transport_method_list); method;
+ method = LIST_NEXT(method, link))
+ if (method->reinit)
+ method->reinit();
+}
+
+/* Initialize the transport maintenance module. */
+void
+transport_init(void)
+{
+ LIST_INIT(&transport_list);
+ LIST_INIT(&transport_method_list);
+}
+
+/* Register another transport T. */
+void
+transport_setup(struct transport *t, int toplevel)
+{
+ if (toplevel) {
+ /* Only the toplevel (virtual) transport has sendqueues. */
+ LOG_DBG((LOG_TRANSPORT, 70,
+ "transport_setup: virtual transport %p", t));
+ TAILQ_INIT(&t->sendq);
+ TAILQ_INIT(&t->prio_sendq);
+ t->refcnt = 0;
+ } else {
+ /* udp and udp_encap trp goes into the transport list. */
+ LOG_DBG((LOG_TRANSPORT, 70,
+ "transport_setup: added %p to transport list", t));
+ LIST_INSERT_HEAD(&transport_list, t, link);
+ t->refcnt = 1;
+ }
+ t->flags = 0;
+}
+
+/* Add a referer to transport T. */
+void
+transport_reference(struct transport *t)
+{
+ t->refcnt++;
+ LOG_DBG((LOG_TRANSPORT, 95,
+ "transport_reference: transport %p now has %d references", t,
+ t->refcnt));
+}
+
+/*
+ * Remove a referer from transport T, removing all of T when no referers left.
+ */
+void
+transport_release(struct transport *t)
+{
+ LOG_DBG((LOG_TRANSPORT, 95,
+ "transport_release: transport %p had %d references", t,
+ t->refcnt));
+ if (--t->refcnt)
+ return;
+
+ LOG_DBG((LOG_TRANSPORT, 70, "transport_release: freeing %p", t));
+ t->vtbl->remove(t);
+}
+
+void
+transport_report(void)
+{
+ struct virtual_transport *v;
+ struct transport *t;
+ struct message *msg;
+
+ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
+ LOG_DBG((LOG_REPORT, 0,
+ "transport_report: transport %p flags %x refcnt %d", t,
+ t->flags, t->refcnt));
+
+ /* XXX Report sth on the virtual transport? */
+ t->vtbl->report(t);
+
+ /*
+ * This is the reason message_dump_raw lives outside
+ * message.c.
+ */
+ v = (struct virtual_transport *)t->virtual;
+ if ((v->encap_is_active && v->encap == t) ||
+ (!v->encap_is_active && v->main == t)) {
+ for (msg = TAILQ_FIRST(&t->virtual->prio_sendq); msg;
+ msg = TAILQ_NEXT(msg, link))
+ message_dump_raw("udp_report(prio)", msg,
+ LOG_REPORT);
+
+ for (msg = TAILQ_FIRST(&t->virtual->sendq); msg;
+ msg = TAILQ_NEXT(msg, link))
+ message_dump_raw("udp_report", msg,
+ LOG_REPORT);
+ }
+ }
+}
+
+int
+transport_prio_sendqs_empty(void)
+{
+ struct transport *t;
+
+ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
+ if (TAILQ_FIRST(&t->virtual->prio_sendq))
+ return 0;
+ return 1;
+}
+
+/* Register another transport method T. */
+void
+transport_method_add(struct transport_vtbl *t)
+{
+ LIST_INSERT_HEAD(&transport_method_list, t, link);
+}
+
+/* Apply a function FUNC on all registered (non-toplevel) transports. */
+void
+transport_map(void (*func) (struct transport *))
+{
+ struct transport *t;
+
+ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
+ (*func) (t);
+}
+
+/*
+ * Build up a file descriptor set FDS with all transport descriptors we want
+ * to read from. Return the number of file descriptors select(2) needs to
+ * check in order to cover the ones we setup in here.
+ */
+int
+transport_fd_set(fd_set * fds)
+{
+ struct transport *t;
+ int n;
+ int max = -1;
+
+ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
+ if (t->virtual->flags & TRANSPORT_LISTEN) {
+ n = t->vtbl->fd_set(t, fds, 1);
+ if (n > max)
+ max = n;
+
+ LOG_DBG((LOG_TRANSPORT, 95, "transport_fd_set: "
+ "transport %p (virtual %p) fd %d", t,
+ t->virtual, n));
+ }
+ return max + 1;
+}
+
+/*
+ * Build up a file descriptor set FDS with all the descriptors belonging to
+ * transport where messages are queued for transmittal. Return the number
+ * of file descriptors select(2) needs to check in order to cover the ones
+ * we setup in here.
+ */
+int
+transport_pending_wfd_set(fd_set * fds)
+{
+ struct transport *t;
+ int n;
+ int max = -1;
+
+ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
+ if (TAILQ_FIRST(&t->virtual->sendq) ||
+ TAILQ_FIRST(&t->virtual->prio_sendq)) {
+ n = t->vtbl->fd_set(t, fds, 1);
+ LOG_DBG((LOG_TRANSPORT, 95,
+ "transport_pending_wfd_set: "
+ "transport %p (virtual %p) fd %d pending", t,
+ t->virtual, n));
+ if (n > max)
+ max = n;
+ }
+ }
+ return max + 1;
+}
+
+/*
+ * For each transport with a file descriptor in FDS, try to get an
+ * incoming message and start processing it.
+ */
+void
+transport_handle_messages(fd_set *fds)
+{
+ struct transport *t;
+
+ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
+ if ((t->flags & TRANSPORT_LISTEN) &&
+ (*t->vtbl->fd_isset)(t, fds)) {
+ (*t->virtual->vtbl->handle_message)(t);
+ (*t->vtbl->fd_set)(t, fds, 0);
+ }
+ }
+}
+
+/*
+ * Send the first queued message on the transports found whose file
+ * descriptor is in FDS and has messages queued. Remove the fd bit from
+ * FDS as soon as one message has been sent on it so other transports
+ * sharing the socket won't get service without an intervening select
+ * call. Perhaps a fairness strategy should be implemented between
+ * such transports. Now early transports in the list will potentially
+ * be favoured to later ones sharing the file descriptor.
+ */
+void
+transport_send_messages(fd_set * fds)
+{
+ struct transport *t, *next;
+ struct message *msg;
+ struct exchange *exchange;
+ struct timeval expiration;
+ int expiry, ok_to_drop_message;
+
+ /*
+ * Reference all transports first so noone will disappear while in
+ * use.
+ */
+ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
+ transport_reference(t->virtual);
+
+ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
+ if ((TAILQ_FIRST(&t->virtual->sendq) ||
+ TAILQ_FIRST(&t->virtual->prio_sendq)) &&
+ t->vtbl->fd_isset(t, fds)) {
+ /* Remove fd bit. */
+ t->vtbl->fd_set(t, fds, 0);
+
+ /* Prefer a message from the prioritized sendq. */
+ if (TAILQ_FIRST(&t->virtual->prio_sendq)) {
+ msg = TAILQ_FIRST(&t->virtual->prio_sendq);
+ TAILQ_REMOVE(&t->virtual->prio_sendq, msg,
+ link);
+ } else {
+ msg = TAILQ_FIRST(&t->virtual->sendq);
+ TAILQ_REMOVE(&t->virtual->sendq, msg, link);
+ }
+
+ msg->flags &= ~MSG_IN_TRANSIT;
+ exchange = msg->exchange;
+ exchange->in_transit = 0;
+
+ /*
+ * We disregard the potential error message here,
+ * hoping that the retransmit will go better.
+ * XXX Consider a retry/fatal error discriminator.
+ */
+ t->virtual->vtbl->send_message(msg, 0);
+ msg->xmits++;
+
+ /*
+ * This piece of code has been proven to be quite
+ * delicate. Think twice for before altering.
+ * Here's an outline:
+ *
+ * If this message is not the one which finishes an
+ * exchange, check if we have reached the number of
+ * retransmit before queuing it up for another.
+ *
+ * If it is a finishing message we still may have to
+ * keep it around for an on-demand retransmit when
+ * seeing a duplicate of our peer's previous message.
+ *
+ */
+ if ((msg->flags & MSG_LAST) == 0) {
+ if (msg->xmits > conf_get_num("General",
+ "retransmits", RETRANSMIT_DEFAULT)) {
+ log_print("transport_send_messages: "
+ "giving up on message %p, "
+ "exchange %s", msg,
+ exchange->name ? exchange->name :
+ "<unnamed>");
+ /* Be more verbose here. */
+ if (exchange->phase == 1) {
+ log_print(
+ "transport_send_messages: "
+ "either this message did "
+ "not reach the other "
+ "peer");
+ if (exchange->initiator)
+ log_print("transport_send_messages: "
+ "or the response"
+ "message did not "
+ "reach us back");
+ else
+ log_print("transport_send_messages: "
+ "or this is an "
+ "attempted IKE "
+ "scan");
+ }
+ exchange->last_sent = 0;
+#ifdef notyet
+ exchange_free(exchange);
+ exchange = 0;
+#endif
+ } else {
+ gettimeofday(&expiration, 0);
+
+ /*
+ * XXX Calculate from round trip
+ * timings and a backoff func.
+ */
+ expiry = msg->xmits * 2 + 5;
+ expiration.tv_sec += expiry;
+ LOG_DBG((LOG_TRANSPORT, 30,
+ "transport_send_messages: "
+ "message %p scheduled for "
+ "retransmission %d in %d secs",
+ msg, msg->xmits, expiry));
+ if (msg->retrans)
+ timer_remove_event(msg->retrans);
+ msg->retrans
+ = timer_add_event("message_send_expire",
+ (void (*) (void *)) message_send_expire,
+ msg, &expiration);
+ /*
+ * If we cannot retransmit, we
+ * cannot...
+ */
+ exchange->last_sent =
+ msg->retrans ? msg : 0;
+ }
+ } else
+ exchange->last_sent =
+ exchange->last_received ? msg : 0;
+
+ /*
+ * If this message is not referred to for later
+ * retransmission it will be ok for us to drop it
+ * after the post-send function. But as the post-send
+ * function may remove the exchange, we need to
+ * remember this fact here.
+ */
+ ok_to_drop_message = exchange->last_sent == 0;
+
+ /*
+ * If this is not a retransmit call post-send
+ * functions that allows parallel work to be done
+ * while the network and peer does their share of
+ * the job. Note that a post-send function may take
+ * away the exchange we belong to, but only if no
+ * retransmits are possible.
+ */
+ if (msg->xmits == 1)
+ message_post_send(msg);
+
+ if (ok_to_drop_message)
+ message_free(msg);
+ }
+ }
+
+ for (t = LIST_FIRST(&transport_list); t; t = next) {
+ next = LIST_NEXT(t, link);
+ transport_release(t->virtual);
+ }
+}
+
+/*
+ * Textual search after the transport method denoted by NAME, then create
+ * a transport connected to the peer with address ADDR, given in a transport-
+ * specific string format.
+ */
+struct transport *
+transport_create(char *name, char *addr)
+{
+ struct transport_vtbl *method;
+
+ for (method = LIST_FIRST(&transport_method_list); method;
+ method = LIST_NEXT(method, link))
+ if (strcmp(method->name, name) == 0)
+ return (*method->create) (addr);
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/transport.h b/keyexchange/isakmpd-20041012/transport.h
new file mode 100644
index 0000000..0a68c73
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/transport.h
@@ -0,0 +1,159 @@
+/* $OpenBSD: transport.h,v 1.15 2004/06/20 15:24:05 ho Exp $ */
+/* $EOM: transport.h,v 1.16 2000/07/17 18:57:59 provos Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * The transport module tries to separate out details concerning the
+ * actual transferral of ISAKMP messages to other parties.
+ */
+
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "message.h"
+
+struct transport;
+
+/* This describes a tranport "method" like UDP or similar. */
+struct transport_vtbl {
+ /* All transport methods are linked together. */
+ LIST_ENTRY(transport_vtbl) link;
+
+ /* A textual name of the transport method. */
+ char *name;
+
+ /* Create a transport instance of this method. */
+ struct transport *(*create) (char *);
+
+ /* Reinitialize specific transport. */
+ void (*reinit) (void);
+
+ /* Remove a transport instance of this method. */
+ void (*remove) (struct transport *);
+
+ /* Report status of given transport */
+ void (*report) (struct transport *);
+
+ /* Let the given transport set it's bit in the fd_set passed in. */
+ int (*fd_set) (struct transport *, fd_set *, int);
+
+ /* Is the given transport ready for I/O? */
+ int (*fd_isset) (struct transport *, fd_set *);
+
+ /*
+ * Read a message from the transport's incoming pipe and start
+ * handling it.
+ */
+ void (*handle_message) (struct transport *);
+
+ /* Send a message through the outgoing pipe. */
+ int (*send_message) (struct message *, struct transport *);
+
+ /*
+ * Fill out a sockaddr structure with the transport's destination end's
+ * address info.
+ */
+ void (*get_dst) (struct transport *, struct sockaddr **);
+
+ /*
+ * Fill out a sockaddr structure with the transport's source end's
+ * address info.
+ */
+ void (*get_src) (struct transport *, struct sockaddr **);
+
+ /*
+ * Return a string with decoded src and dst information
+ */
+ char *(*decode_ids) (struct transport *);
+
+ /*
+ * Clone a transport for outbound use.
+ */
+ struct transport *(*clone) (struct transport *, struct sockaddr *);
+
+ /*
+ * Locate the correct sendq to use for outbound messages.
+ */
+ struct msg_head *(*get_queue) (struct message *);
+};
+
+struct transport {
+ /* All transports used are linked together. */
+ LIST_ENTRY(transport) link;
+
+ /* What transport method is this an instance of? */
+ struct transport_vtbl *vtbl;
+
+ /* The queue holding messages to send on this transport. */
+ struct msg_head sendq;
+
+ /*
+ * Prioritized send queue. Messages in this queue will be transmitted
+ * before the normal sendq, they will also all be transmitted prior
+ * to a daemon shutdown. Currently only used for DELETE notifications.
+ */
+ struct msg_head prio_sendq;
+
+ /* Flags describing the transport. */
+ int flags;
+
+ /* Reference counter. */
+ int refcnt;
+
+ /* Pointer to parent virtual transport, if any. */
+ struct transport *virtual;
+};
+
+/* Set if this is a transport we want to listen on. */
+#define TRANSPORT_LISTEN 1
+/* Used for mark-and-sweep-type garbage collection of transports */
+#define TRANSPORT_MARK 2
+
+extern struct transport *transport_create(char *, char *);
+extern int transport_fd_set(fd_set *);
+extern void transport_handle_messages(fd_set *);
+extern void transport_init(void);
+extern void transport_map(void (*) (struct transport *));
+extern void transport_method_add(struct transport_vtbl *);
+extern int transport_pending_wfd_set(fd_set *);
+extern int transport_prio_sendqs_empty(void);
+extern void transport_reference(struct transport *);
+extern void transport_reinit(void);
+extern void transport_release(struct transport *);
+extern void transport_report(void);
+extern void transport_send_messages(fd_set *);
+extern void transport_setup(struct transport *, int);
+#endif /* _TRANSPORT_H_ */
diff --git a/keyexchange/isakmpd-20041012/udp.c b/keyexchange/isakmpd-20041012/udp.c
new file mode 100644
index 0000000..090297b
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/udp.c
@@ -0,0 +1,573 @@
+/* $OpenBSD: udp.c,v 1.79 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: udp.c,v 1.57 2001/01/26 10:09:57 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2003, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifndef linux
+#include <sys/sockio.h>
+#endif
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "if.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#include "monitor.h"
+#include "sysdep.h"
+#include "transport.h"
+#include "udp.h"
+#include "util.h"
+#include "virtual.h"
+
+#define UDP_SIZE 65536
+
+/* If a system doesn't have SO_REUSEPORT, SO_REUSEADDR will have to do. */
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT SO_REUSEADDR
+#endif
+
+/* These are reused by udp_encap.c, thus not 'static' here. */
+struct transport *udp_clone(struct transport *, struct sockaddr *);
+int udp_fd_set(struct transport *, fd_set *, int);
+int udp_fd_isset(struct transport *, fd_set *);
+void udp_get_dst(struct transport *, struct sockaddr **);
+void udp_get_src(struct transport *, struct sockaddr **);
+char *udp_decode_ids(struct transport *);
+void udp_remove(struct transport *);
+
+static struct transport *udp_create(char *);
+static void udp_report(struct transport *);
+static void udp_handle_message(struct transport *);
+static struct transport *udp_make(struct sockaddr *);
+static int udp_send_message(struct message *, struct transport *);
+#if 0
+static in_port_t udp_decode_port(char *);
+#endif
+
+static struct transport_vtbl udp_transport_vtbl = {
+ {0}, "udp_physical",
+ udp_create,
+ 0,
+ udp_remove,
+ udp_report,
+ udp_fd_set,
+ udp_fd_isset,
+ udp_handle_message,
+ udp_send_message,
+ udp_get_dst,
+ udp_get_src,
+ udp_decode_ids,
+ udp_clone,
+ 0
+};
+
+char *udp_default_port = 0;
+char *udp_bind_port = 0;
+int bind_family = 0;
+
+void
+udp_init(void)
+{
+ transport_method_add(&udp_transport_vtbl);
+}
+
+/* Create a UDP transport structure bound to LADDR just for listening. */
+static struct transport *
+udp_make(struct sockaddr *laddr)
+{
+ struct udp_transport *t = 0;
+ int s, on, wildcardaddress = 0;
+ char *tstr;
+
+ t = calloc(1, sizeof *t);
+ if (!t) {
+ log_print("udp_make: calloc (1, %lu) failed",
+ (unsigned long)sizeof *t);
+ free(laddr);
+ return 0;
+ }
+ t->src = laddr;
+
+ s = socket(laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1) {
+ log_error("udp_make: socket (%d, %d, %d)", laddr->sa_family,
+ SOCK_DGRAM, IPPROTO_UDP);
+ goto err;
+ }
+ /* Make sure we don't get our traffic encrypted. */
+ if (sysdep_cleartext(s, laddr->sa_family) == -1)
+ goto err;
+
+ /* Wildcard address ? */
+ switch (laddr->sa_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *)laddr)->sin_addr.s_addr ==
+ INADDR_ANY)
+ wildcardaddress = 1;
+ break;
+ case AF_INET6:
+ if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)laddr)->sin6_addr))
+ wildcardaddress = 1;
+ break;
+ }
+
+ /*
+ * In order to have several bound specific address-port combinations
+ * with the same port SO_REUSEADDR is needed. If this is a wildcard
+ * socket and we are not listening there, but only sending from it
+ * make sure it is entirely reuseable with SO_REUSEPORT.
+ */
+ on = 1;
+ if (setsockopt(s, SOL_SOCKET,
+ wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR,
+ (void *)&on, sizeof on) == -1) {
+ log_error("udp_make: setsockopt (%d, %d, %d, %p, %lu)", s,
+ SOL_SOCKET, wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR,
+ &on, (unsigned long)sizeof on);
+ goto err;
+ }
+ t->transport.vtbl = &udp_transport_vtbl;
+ if (monitor_bind(s, t->src, sysdep_sa_len(t->src))) {
+ if (sockaddr2text(t->src, &tstr, 0))
+ log_error("udp_make: bind (%d, %p, %lu)", s, &t->src,
+ (unsigned long)sizeof t->src);
+ else {
+ log_error("udp_make: bind (%d, %s, %lu)", s, tstr,
+ (unsigned long)sizeof t->src);
+ free(tstr);
+ }
+ goto err;
+ }
+ t->s = s;
+ if (sockaddr2text(t->src, &tstr, 0))
+ LOG_DBG((LOG_MISC, 20, "udp_make: "
+ "transport %p socket %d family %d", t, s,
+ t->src->sa_family == AF_INET ? 4 : 6));
+ else {
+ LOG_DBG((LOG_MISC, 20, "udp_make: "
+ "transport %p socket %d ip %s port %d", t, s,
+ tstr, ntohs(sockaddr_port(t->src))));
+ free (tstr);
+ }
+ transport_setup(&t->transport, 0);
+ t->transport.flags |= TRANSPORT_LISTEN;
+ return &t->transport;
+
+err:
+ if (s >= 0)
+ close(s);
+ if (t) {
+ /* Already closed. */
+ t->s = -1;
+ udp_remove(&t->transport);
+ }
+ return 0;
+}
+
+/* Clone a listen transport U, record a destination RADDR for outbound use. */
+struct transport *
+udp_clone(struct transport *ut, struct sockaddr *raddr)
+{
+ struct udp_transport *u = (struct udp_transport *)ut;
+ struct udp_transport *u2;
+ struct transport *t;
+
+ t = malloc(sizeof *u);
+ if (!t) {
+ log_error("udp_clone: malloc (%lu) failed",
+ (unsigned long)sizeof *u);
+ return 0;
+ }
+ u2 = (struct udp_transport *)t;
+
+ memcpy(u2, u, sizeof *u);
+
+ u2->src = malloc(sysdep_sa_len(u->src));
+ if (!u2->src) {
+ log_error("udp_clone: malloc (%d) failed",
+ sysdep_sa_len(u->src));
+ free(t);
+ return 0;
+ }
+ memcpy(u2->src, u->src, sysdep_sa_len(u->src));
+
+ u2->dst = malloc(sysdep_sa_len(raddr));
+ if (!u2->dst) {
+ log_error("udp_clone: malloc (%d) failed",
+ sysdep_sa_len(raddr));
+ free(u2->src);
+ free(t);
+ return 0;
+ }
+ memcpy(u2->dst, raddr, sysdep_sa_len(raddr));
+
+ t->flags &= ~TRANSPORT_LISTEN;
+ transport_setup(t, 0);
+ return t;
+}
+
+/*
+ * Initialize an object of the UDP transport class. Fill in the local
+ * IP address and port information and create a server socket bound to
+ * that specific port. Add the polymorphic transport structure to the
+ * system-wide pools of known ISAKMP transports.
+ */
+struct transport *
+udp_bind(const struct sockaddr *addr)
+{
+ struct sockaddr *src;
+
+ src = malloc(sysdep_sa_len((struct sockaddr *)addr));
+ if (!src)
+ return 0;
+
+ memcpy(src, addr, sysdep_sa_len((struct sockaddr *)addr));
+ return udp_make(src);
+}
+
+/*
+ * NAME is a section name found in the config database. Setup and return
+ * a transport useable to talk to the peer specified by that name.
+ */
+static struct transport *
+udp_create(char *name)
+{
+ struct virtual_transport *v;
+ struct udp_transport *u;
+ struct transport *rv, *t;
+ struct sockaddr *dst, *addr;
+ char *addr_str, *port_str;
+ struct conf_list *addr_list = 0;
+ struct conf_list_node *addr_node;
+
+ port_str = conf_get_str(name, "Port");
+ if (!port_str)
+ port_str = udp_default_port;
+ if (!port_str)
+ port_str = UDP_DEFAULT_PORT_STR;
+
+ addr_str = conf_get_str(name, "Address");
+ if (!addr_str) {
+ log_print("udp_create: no address configured for \"%s\"",
+ name);
+ return 0;
+ }
+ if (text2sockaddr(addr_str, port_str, &dst)) {
+ log_print("udp_create: address \"%s\" not understood",
+ addr_str);
+ return 0;
+ }
+ addr_str = conf_get_str(name, "Local-address");
+ if (!addr_str)
+ addr_list = conf_get_list("General", "Listen-on");
+ if (!addr_str && !addr_list) {
+ v = virtual_get_default(dst->sa_family);
+ u = (struct udp_transport *)v->main;
+
+ if (!u) {
+ log_print("udp_create: no default transport");
+ rv = 0;
+ goto ret;
+ } else {
+ rv = udp_clone((struct transport *)u, dst);
+ if (rv)
+ rv->vtbl = &udp_transport_vtbl;
+ goto ret;
+ }
+ }
+
+ if (addr_list) {
+ for (addr_node = TAILQ_FIRST(&addr_list->fields);
+ addr_node; addr_node = TAILQ_NEXT(addr_node, link))
+ if (text2sockaddr(addr_node->field, port_str, &addr)
+ == 0) {
+ v = virtual_listen_lookup(addr);
+ free(addr);
+ if (v) {
+ addr_str = addr_node->field;
+ break;
+ }
+ }
+ if (!addr_str) {
+ log_print("udp_create: no matching listener found");
+ rv = 0;
+ goto ret;
+ }
+ }
+ if (text2sockaddr(addr_str, port_str, &addr)) {
+ log_print("udp_create: address \"%s\" not understood",
+ addr_str);
+ rv = 0;
+ goto ret;
+ }
+
+ v = virtual_listen_lookup(addr);
+ free(addr);
+ if (!v) {
+ log_print("udp_create: %s:%s must exist as a listener too",
+ addr_str, port_str);
+ rv = 0;
+ goto ret;
+ }
+ t = (struct transport *)v;
+ rv = udp_clone(v->main, dst);
+ if (rv)
+ rv->vtbl = &udp_transport_vtbl;
+
+ret:
+ if (addr_list)
+ conf_free_list(addr_list);
+ free(dst);
+ return rv;
+}
+
+void
+udp_remove(struct transport *t)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+
+ if (u->src)
+ free(u->src);
+ if (u->dst)
+ free(u->dst);
+ if ((t->flags & TRANSPORT_LISTEN) && u->s >= 0)
+ close(u->s);
+ if (t->link.le_prev)
+ LIST_REMOVE(t, link);
+
+ LOG_DBG((LOG_TRANSPORT, 90, "udp_remove: removed transport %p", t));
+ free(t);
+}
+
+/* Report transport-method specifics of the T transport. */
+void
+udp_report(struct transport *t)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+ char *src = NULL, *dst = NULL;
+ in_port_t sport, dport;
+
+ if (sockaddr2text(u->src, &src, 0))
+ goto ret;
+ sport = sockaddr_port(u->src);
+
+ if (!u->dst || sockaddr2text(u->dst, &dst, 0))
+ dst = 0;
+ dport = dst ? sockaddr_port(u->dst) : 0;
+
+ LOG_DBG((LOG_REPORT, 0, "udp_report: fd %d src %s:%u dst %s:%u", u->s,
+ src, ntohs(sport), dst ? dst : "<none>", ntohs(dport)));
+
+ret:
+ if (dst)
+ free(dst);
+ if (src)
+ free(src);
+}
+
+/*
+ * A message has arrived on transport T's socket. If T is single-ended,
+ * clone it into a double-ended transport which we will use from now on.
+ * Package the message as we want it and continue processing in the message
+ * module.
+ */
+static void
+udp_handle_message(struct transport *t)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+ u_int8_t buf[UDP_SIZE];
+ struct sockaddr_storage from;
+ u_int32_t len = sizeof from;
+ ssize_t n;
+ struct message *msg;
+
+ n = recvfrom(u->s, buf, UDP_SIZE, 0, (struct sockaddr *)&from, &len);
+ if (n == -1) {
+ log_error("recvfrom (%d, %p, %d, %d, %p, %p)", u->s, buf,
+ UDP_SIZE, 0, &from, &len);
+ return;
+ }
+ /*
+ * Make a specialized UDP transport structure out of the incoming
+ * transport and the address information we got from recvfrom(2).
+ */
+ t = t->virtual->vtbl->clone(t->virtual, (struct sockaddr *)&from);
+ if (!t)
+ return;
+
+ msg = message_alloc(t, buf, n);
+ if (!msg) {
+ log_error("failed to allocate message structure, dropping "
+ "packet received on transport %p", u);
+ t->vtbl->remove(t);
+ return;
+ }
+ message_recv(msg);
+}
+
+/* Physically send the message MSG over its associated transport. */
+static int
+udp_send_message(struct message *msg, struct transport *t)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+ ssize_t n;
+ struct msghdr m;
+
+ /*
+ * Sending on connected sockets requires that no destination address is
+ * given, or else EISCONN will occur.
+ */
+ m.msg_name = (caddr_t) u->dst;
+ m.msg_namelen = sysdep_sa_len(u->dst);
+ m.msg_iov = msg->iov;
+ m.msg_iovlen = msg->iovlen;
+ m.msg_control = 0;
+ m.msg_controllen = 0;
+ m.msg_flags = 0;
+ n = sendmsg(u->s, &m, 0);
+ if (n == -1) {
+ /* XXX We should check whether the address has gone away */
+ log_error("sendmsg (%d, %p, %d)", u->s, &m, 0);
+ return -1;
+ }
+ return 0;
+}
+
+int
+udp_fd_set(struct transport *t, fd_set *fds, int bit)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+
+ if (bit)
+ FD_SET(u->s, fds);
+ else
+ FD_CLR(u->s, fds);
+
+ return u->s + 1;
+}
+
+int
+udp_fd_isset(struct transport *t, fd_set *fds)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+
+ return FD_ISSET(u->s, fds);
+}
+
+/*
+ * Get transport T's peer address and stuff it into the sockaddr pointed
+ * to by DST.
+ */
+void
+udp_get_dst(struct transport *t, struct sockaddr **dst)
+{
+ *dst = ((struct udp_transport *)t)->dst;
+}
+
+/*
+ * Get transport T's local address and stuff it into the sockaddr pointed
+ * to by SRC. Put its length into SRC_LEN.
+ */
+void
+udp_get_src(struct transport *t, struct sockaddr **src)
+{
+ *src = ((struct udp_transport *)t)->src;
+}
+
+char *
+udp_decode_ids(struct transport *t)
+{
+ struct sockaddr *src, *dst;
+ static char result[1024];
+ char idsrc[256], iddst[256];
+
+ t->vtbl->get_src(t, &src);
+ t->vtbl->get_dst(t, &dst);
+
+ if (getnameinfo(src, sysdep_sa_len(src), idsrc, sizeof idsrc, NULL, 0,
+ NI_NUMERICHOST) != 0) {
+ log_print("udp_decode_ids: getnameinfo () failed for 'src'");
+ strlcpy(idsrc, "<error>", 256);
+ }
+ if (getnameinfo(dst, sysdep_sa_len(dst), iddst, sizeof iddst, NULL, 0,
+ NI_NUMERICHOST) != 0) {
+ log_print("udp_decode_ids: getnameinfo () failed for 'dst'");
+ strlcpy(iddst, "<error>", 256);
+ }
+
+ snprintf(result, sizeof result, "src: %s dst: %s", idsrc, iddst);
+ return result;
+}
+
+#if 0
+/*
+ * Take a string containing an ext representation of port and return a
+ * binary port number in host byte order. Return zero if anything goes wrong.
+ * XXX Currently unused.
+ */
+static in_port_t
+udp_decode_port(char *port_str)
+{
+ char *port_str_end;
+ long port_long;
+ struct servent *service;
+
+ port_long = ntohl(strtol(port_str, &port_str_end, 0));
+ if (port_str == port_str_end) {
+ service = getservbyname(port_str, "udp");
+ if (!service) {
+ log_print("udp_decode_port: service \"%s\" unknown",
+ port_str);
+ return 0;
+ }
+ return ntohs(service->s_port);
+ } else if (port_long < 1 || port_long > 65535) {
+ log_print("udp_decode_port: port %ld out of range", port_long);
+ return 0;
+ }
+ return port_long;
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/udp.h b/keyexchange/isakmpd-20041012/udp.h
new file mode 100644
index 0000000..dd91a6c
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/udp.h
@@ -0,0 +1,52 @@
+/* $OpenBSD: udp.h,v 1.10 2004/08/03 10:54:09 ho Exp $ */
+/* $EOM: udp.h,v 1.4 1998/12/22 02:23:43 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _UDP_H_
+#define _UDP_H_
+
+extern char *udp_default_port;
+extern char *udp_bind_port;
+extern int bind_family;
+
+#define BIND_FAMILY_INET4 0x0001
+#define BIND_FAMILY_INET6 0x0002
+
+struct transport *udp_bind(const struct sockaddr *);
+void udp_init(void);
+
+struct udp_transport {
+ struct transport transport;
+ struct sockaddr *src;
+ struct sockaddr *dst;
+ int s;
+};
+
+#endif /* _UDP_H_ */
diff --git a/keyexchange/isakmpd-20041012/udp_encap.c b/keyexchange/isakmpd-20041012/udp_encap.c
new file mode 100644
index 0000000..92f6404
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/udp_encap.c
@@ -0,0 +1,473 @@
+/* $OpenBSD: udp_encap.c,v 1.8 2004/09/24 13:31:04 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifndef linux
+#include <sys/sockio.h>
+#endif
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "if.h"
+#include "ipsec_doi.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#include "monitor.h"
+#include "sysdep.h"
+#include "transport.h"
+#include "udp.h"
+#include "udp_encap.h"
+#include "util.h"
+#include "virtual.h"
+
+#define UDP_SIZE 65536
+
+#if defined(USE_NAT_TRAVERSAL) && defined (LINUX_IPSEC)
+#include <linux/socket.h>
+#include <linux/udp.h>
+#endif
+
+/* If a system doesn't have SO_REUSEPORT, SO_REUSEADDR will have to do. */
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT SO_REUSEADDR
+#endif
+
+/* Reused, from udp.c */
+struct transport *udp_clone(struct transport *, struct sockaddr *);
+int udp_fd_set(struct transport *, fd_set *, int);
+int udp_fd_isset(struct transport *, fd_set *);
+void udp_get_dst(struct transport *, struct sockaddr **);
+void udp_get_src(struct transport *, struct sockaddr **);
+char *udp_decode_ids(struct transport *);
+void udp_remove(struct transport *);
+
+static struct transport *udp_encap_create(char *);
+static void udp_encap_report(struct transport *);
+static void udp_encap_handle_message(struct transport *);
+static struct transport *udp_encap_make(struct sockaddr *);
+static int udp_encap_send_message(struct message *,
+ struct transport *);
+
+static struct transport_vtbl udp_encap_transport_vtbl = {
+ { 0 }, "udp_encap",
+ udp_encap_create,
+ 0,
+ udp_remove,
+ udp_encap_report,
+ udp_fd_set,
+ udp_fd_isset,
+ udp_encap_handle_message,
+ udp_encap_send_message,
+ udp_get_dst,
+ udp_get_src,
+ udp_decode_ids,
+ udp_clone,
+ 0
+};
+
+char *udp_encap_default_port = 0;
+char *udp_encap_bind_port = 0;
+
+void
+udp_encap_init(void)
+{
+ transport_method_add(&udp_encap_transport_vtbl);
+}
+
+/* Create a UDP transport structure bound to LADDR just for listening. */
+static struct transport *
+udp_encap_make(struct sockaddr *laddr)
+{
+ struct udp_transport *t = 0;
+ int s, on, wildcardaddress = 0;
+ char *tstr;
+
+ t = calloc(1, sizeof *t);
+ if (!t) {
+ log_print("udp_encap_make: malloc (%lu) failed",
+ (unsigned long)sizeof *t);
+ return 0;
+ }
+
+ s = socket(laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1) {
+ log_error("udp_encap_make: socket (%d, %d, %d)",
+ laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+ goto err;
+ }
+
+ /* Make sure we don't get our traffic encrypted. */
+ if (sysdep_cleartext(s, laddr->sa_family) == -1)
+ goto err;
+
+#if defined(USE_NAT_TRAVERSAL) && defined (LINUX_IPSEC)
+ {
+#ifndef SOL_UDP
+#define SOL_UDP 17
+#endif
+ int option = UDP_ENCAP_ESPINUDP;
+ if(setsockopt(s, SOL_UDP, UDP_ENCAP, &option,
+ sizeof (option)) < 0)
+ goto err;
+ }
+#endif
+
+ /* Wildcard address ? */
+ switch (laddr->sa_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *)laddr)->sin_addr.s_addr
+ == INADDR_ANY)
+ wildcardaddress = 1;
+ break;
+ case AF_INET6:
+ if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)laddr)->sin6_addr))
+ wildcardaddress = 1;
+ break;
+ }
+
+ /*
+ * In order to have several bound specific address-port combinations
+ * with the same port SO_REUSEADDR is needed.
+ * If this is a wildcard socket and we are not listening there, but
+ * only sending from it make sure it is entirely reuseable with
+ * SO_REUSEPORT.
+ */
+ on = 1;
+ if (setsockopt(s, SOL_SOCKET,
+ wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR,
+ (void *)&on, sizeof on) == -1) {
+ log_error("udp_encap_make: setsockopt (%d, %d, %d, %p, %lu)",
+ s, SOL_SOCKET,
+ wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, &on,
+ (unsigned long)sizeof on);
+ goto err;
+ }
+
+ t->transport.vtbl = &udp_encap_transport_vtbl;
+ t->src = laddr;
+ if (monitor_bind(s, t->src, sysdep_sa_len (t->src))) {
+ if (sockaddr2text(t->src, &tstr, 0))
+ log_error("udp_encap_make: bind (%d, %p, %lu)", s,
+ &t->src, (unsigned long)sizeof t->src);
+ else {
+ log_error("udp_encap_make: bind (%d, %s, %lu)", s,
+ tstr, (unsigned long)sizeof t->src);
+ free(tstr);
+ }
+ goto err;
+ }
+
+ t->s = s;
+ if (sockaddr2text(t->src, &tstr, 0))
+ LOG_DBG((LOG_MISC, 20, "udp_encap_make: "
+ "transport %p socket %d family %d", t, s,
+ t->src->sa_family == AF_INET ? 4 : 6));
+ else {
+ LOG_DBG((LOG_MISC, 20, "udp_encap_make: "
+ "transport %p socket %d ip %s port %d", t, s,
+ tstr, ntohs(sockaddr_port(t->src))));
+ free(tstr);
+ }
+ transport_setup(&t->transport, 0);
+ t->transport.flags |= TRANSPORT_LISTEN;
+ return &t->transport;
+
+err:
+ if (s >= 0)
+ close (s);
+ if (t) {
+ /* Already closed. */
+ t->s = -1;
+ udp_remove(&t->transport);
+ }
+ return 0;
+}
+
+/*
+ * Initialize an object of the UDP transport class. Fill in the local
+ * IP address and port information and create a server socket bound to
+ * that specific port. Add the polymorphic transport structure to the
+ * system-wide pools of known ISAKMP transports.
+ */
+struct transport *
+udp_encap_bind(const struct sockaddr *addr)
+{
+ struct sockaddr *src =
+ malloc(sysdep_sa_len((struct sockaddr *)addr));
+
+ if (!src)
+ return 0;
+
+ memcpy(src, addr, sysdep_sa_len((struct sockaddr *)addr));
+ return udp_encap_make(src);
+}
+
+/*
+ * NAME is a section name found in the config database. Setup and return
+ * a transport useable to talk to the peer specified by that name.
+ */
+static struct transport *
+udp_encap_create(char *name)
+{
+ struct virtual_transport *v;
+ struct udp_transport *u;
+ struct transport *rv, *t;
+ struct sockaddr *dst, *addr;
+ struct conf_list *addr_list = 0;
+ struct conf_list_node *addr_node;
+ char *addr_str, *port_str;
+
+ port_str = conf_get_str(name, "Port"); /* XXX "Encap-port" ? */
+ if (!port_str)
+ port_str = udp_encap_default_port;
+ if (!port_str)
+ port_str = UDP_ENCAP_DEFAULT_PORT_STR;
+
+ addr_str = conf_get_str(name, "Address");
+ if (!addr_str) {
+ log_print("udp_encap_create: no address configured "
+ "for \"%s\"", name);
+ return 0;
+ }
+ if (text2sockaddr(addr_str, port_str, &dst)) {
+ log_print("udp_encap_create: address \"%s\" not understood",
+ addr_str);
+ return 0;
+ }
+
+ addr_str = conf_get_str(name, "Local-address");
+ if (!addr_str)
+ addr_list = conf_get_list("General", "Listen-on");
+ if (!addr_str && !addr_list) {
+ v = virtual_get_default(dst->sa_family);
+ u = (struct udp_transport *)v->encap;
+
+ if (!u) {
+ log_print("udp_encap_create: no default transport");
+ rv = 0;
+ goto ret;
+ } else {
+ rv = udp_clone((struct transport *)u, dst);
+ if (rv)
+ rv->vtbl = &udp_encap_transport_vtbl;
+ goto ret;
+ }
+ }
+
+ if (addr_list) {
+ for (addr_node = TAILQ_FIRST(&addr_list->fields);
+ addr_node; addr_node = TAILQ_NEXT(addr_node, link))
+ if (text2sockaddr(addr_node->field, port_str,
+ &addr) == 0) {
+ v = virtual_listen_lookup(addr);
+ free(addr);
+ if (v) {
+ addr_str = addr_node->field;
+ break;
+ }
+ }
+ if (!addr_str) {
+ log_print("udp_encap_create: "
+ "no matching listener found");
+ rv = 0;
+ goto ret;
+ }
+ }
+ if (text2sockaddr(addr_str, port_str, &addr)) {
+ log_print("udp_encap_create: "
+ "address \"%s\" not understood", addr_str);
+ rv = 0;
+ goto ret;
+ }
+ v = virtual_listen_lookup(addr);
+ free(addr);
+ if (!v) {
+ log_print("udp_encap_create: "
+ "%s:%s must exist as a listener too", addr_str, port_str);
+ rv = 0;
+ goto ret;
+ }
+ t = (struct transport *)v;
+ rv = udp_clone(v->encap, dst);
+ if (rv)
+ rv->vtbl = &udp_encap_transport_vtbl;
+
+ret:
+ if (addr_list)
+ conf_free_list(addr_list);
+ free(dst);
+ return rv;
+}
+
+/* Report transport-method specifics of the T transport. */
+void
+udp_encap_report(struct transport *t)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+ char *src, *dst;
+ in_port_t sport, dport;
+
+ if (sockaddr2text(u->src, &src, 0))
+ goto ret;
+ sport = sockaddr_port(u->src);
+
+ if (!u->dst || sockaddr2text(u->dst, &dst, 0))
+ dst = 0;
+ dport = dst ? sockaddr_port(u->dst) : 0;
+
+ LOG_DBG ((LOG_REPORT, 0, "udp_encap_report: fd %d src %s:%u dst %s:%u",
+ u->s, src, ntohs(sport), dst ? dst : "*", ntohs(dport)));
+
+ ret:
+ if (dst)
+ free(dst);
+ if (src)
+ free(src);
+}
+
+/*
+ * A message has arrived on transport T's socket. If T is single-ended,
+ * clone it into a double-ended transport which we will use from now on.
+ * Package the message as we want it and continue processing in the message
+ * module.
+ */
+static void
+udp_encap_handle_message(struct transport *t)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+ struct sockaddr_storage from;
+ struct message *msg;
+ u_int32_t len = sizeof from;
+ ssize_t n;
+ u_int8_t buf[UDP_SIZE];
+
+ n = recvfrom(u->s, buf, UDP_SIZE, 0, (struct sockaddr *)&from, &len);
+ if (n == -1) {
+ log_error("recvfrom (%d, %p, %d, %d, %p, %p)", u->s, buf,
+ UDP_SIZE, 0, &from, &len);
+ return;
+ }
+
+ /*
+ * Make a specialized UDP transport structure out of the incoming
+ * transport and the address information we got from recvfrom(2).
+ */
+ t = t->virtual->vtbl->clone(t->virtual, (struct sockaddr *)&from);
+ if (!t)
+ return;
+
+ /* Check NULL-ESP marker. */
+ if (n < (ssize_t)sizeof(u_int32_t) || *(u_int32_t *)buf != 0) {
+ /* Should never happen. */
+ log_print("udp_encap_handle_message: "
+ "Null-ESP marker not NULL or short message");
+ return;
+ }
+
+ /* NAT-Keepalive messages should not be processed further. */
+ n -= sizeof(u_int32_t);
+ if (n == 1 && buf[sizeof(u_int32_t)] == 0xFF)
+ return;
+
+ msg = message_alloc(t, buf + sizeof (u_int32_t), n);
+ if (!msg) {
+ log_error("failed to allocate message structure, dropping "
+ "packet received on transport %p", u);
+ return;
+ }
+ message_recv(msg);
+}
+
+/*
+ * Physically send the message MSG over its associated transport.
+ * Special: if 'msg' is NULL, send a NAT-T keepalive message.
+ */
+static int
+udp_encap_send_message(struct message *msg, struct transport *t)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+ struct msghdr m;
+ struct iovec *new_iov = 0, keepalive;
+ ssize_t n;
+ u_int32_t marker = 0; /* NULL-ESP Marker */
+
+ if (msg) {
+ /* Construct new iov array, prefixing NULL-ESP Marker. */
+ new_iov = (struct iovec *)calloc (msg->iovlen + 1,
+ sizeof *new_iov);
+ if (!new_iov) {
+ log_error ("udp_encap_send_message: "
+ "calloc (%lu, %lu) failed",
+ (unsigned long)msg->iovlen + 1,
+ (unsigned long)sizeof *new_iov);
+ return -1;
+ }
+ new_iov[0].iov_base = &marker;
+ new_iov[0].iov_len = IPSEC_SPI_SIZE;
+ memcpy (new_iov + 1, msg->iov, msg->iovlen * sizeof *new_iov);
+ } else {
+ marker = ~marker;
+ keepalive.iov_base = &marker;
+ keepalive.iov_len = 1;
+ }
+
+ /*
+ * Sending on connected sockets requires that no destination address is
+ * given, or else EISCONN will occur.
+ */
+ m.msg_name = (caddr_t)u->dst;
+ m.msg_namelen = sysdep_sa_len (u->dst);
+ m.msg_iov = msg ? new_iov : &keepalive;
+ m.msg_iovlen = msg ? msg->iovlen + 1 : 1;
+ m.msg_control = 0;
+ m.msg_controllen = 0;
+ m.msg_flags = 0;
+ n = sendmsg (u->s, &m, 0);
+ if (msg)
+ free (new_iov);
+ if (n == -1) {
+ /* XXX We should check whether the address has gone away */
+ log_error ("sendmsg (%d, %p, %d)", u->s, &m, 0);
+ return -1;
+ }
+ return 0;
+}
diff --git a/keyexchange/isakmpd-20041012/udp_encap.h b/keyexchange/isakmpd-20041012/udp_encap.h
new file mode 100644
index 0000000..bb08db2
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/udp_encap.h
@@ -0,0 +1,37 @@
+/* $OpenBSD: udp_encap.h,v 1.1 2004/06/20 15:24:05 ho Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _UDP_ENCAP_H_
+#define _UDP_ENCAP_H_
+
+struct transport *udp_encap_bind (const struct sockaddr *);
+void udp_encap_init (void);
+
+extern char *udp_encap_default_port;
+extern char *udp_encap_bind_port;
+
+#endif /* _UDP_H_ */
diff --git a/keyexchange/isakmpd-20041012/ui.c b/keyexchange/isakmpd-20041012/ui.c
new file mode 100644
index 0000000..7167873
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ui.c
@@ -0,0 +1,528 @@
+/* $OpenBSD: ui.c,v 1.42 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: ui.c,v 1.43 2000/10/05 09:25:12 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001, 2002 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "sysdep.h"
+
+#include "conf.h"
+#include "connection.h"
+#include "doi.h"
+#include "exchange.h"
+#include "init.h"
+#include "isakmp.h"
+#include "log.h"
+#include "monitor.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "ui.h"
+#include "util.h"
+
+#define BUF_SZ 256
+
+/* from isakmpd.c */
+void daemon_shutdown_now(int);
+
+/* Report all SA configuration information. */
+void ui_report_sa(char *);
+
+static FILE *ui_open_result(void);
+
+char *ui_fifo = FIFO;
+int ui_socket;
+struct event *ui_cr_event = NULL;
+
+/* Create and open the FIFO used for user control. */
+void
+ui_init(void)
+{
+ struct stat st;
+
+ /* -f- means control messages comes in via stdin. */
+ if (strcmp(ui_fifo, "-") == 0) {
+ ui_socket = 0;
+ return;
+ }
+
+ /* Don't overwrite a file, i.e '-f /etc/isakmpd/isakmpd.conf'. */
+ if (lstat(ui_fifo, &st) == 0) {
+ if ((st.st_mode & S_IFMT) == S_IFREG) {
+ errno = EEXIST;
+ log_fatal("ui_init: could not create FIFO \"%s\"",
+ ui_fifo);
+ }
+ }
+
+ /* No need to know about errors. */
+ unlink(ui_fifo);
+ if (mkfifo(ui_fifo, 0600) == -1)
+ log_fatal("ui_init: mkfifo (\"%s\", 0600) failed", ui_fifo);
+
+ ui_socket = open(ui_fifo, O_RDWR | O_NONBLOCK, 0);
+ if (ui_socket == -1)
+ log_fatal("ui_init: open (\"%s\", O_RDWR | O_NONBLOCK, 0) "
+ "failed", ui_fifo);
+}
+
+/*
+ * Setup a phase 2 connection.
+ * XXX Maybe phase 1 works too, but teardown won't work then, fix?
+ */
+static void
+ui_connect(char *cmd)
+{
+ char name[81];
+
+ if (sscanf(cmd, "c %80s", name) != 1) {
+ log_print("ui_connect: command \"%s\" malformed", cmd);
+ return;
+ }
+ LOG_DBG((LOG_UI, 10, "ui_connect: setup connection \"%s\"", name));
+ connection_setup(name);
+}
+
+/* Tear down a phase 2 connection. */
+static void
+ui_teardown(char *cmd)
+{
+ char name[81];
+ struct sa *sa;
+
+ if (sscanf(cmd, "t %80s", name) != 1) {
+ log_print("ui_teardown: command \"%s\" malformed", cmd);
+ return;
+ }
+ LOG_DBG((LOG_UI, 10, "ui_teardown: teardown connection \"%s\"", name));
+ connection_teardown(name);
+ while ((sa = sa_lookup_by_name(name, 2)) != 0)
+ sa_delete(sa, 1);
+}
+
+/* Tear down all phase 2 connections. */
+static void
+ui_teardown_all(char *cmd)
+{
+ /* Skip 'cmd' as arg. */
+ sa_teardown_all();
+}
+
+static void
+ui_conn_reinit_event(void *v)
+{
+ /*
+ * This event is required for isakmpd to reinitialize the connection
+ * and passive-connection lists. Otherwise a change to the
+ * "[Phase 2]:Connections" tag will not have any effect.
+ */
+ connection_reinit();
+
+ ui_cr_event = NULL;
+}
+
+static void
+ui_conn_reinit(void)
+{
+ struct timeval tv;
+
+ if (ui_cr_event)
+ timer_remove_event(ui_cr_event);
+
+ gettimeofday(&tv, 0);
+ tv.tv_sec += 5;
+
+ ui_cr_event = timer_add_event("ui_conn_reinit", ui_conn_reinit_event,
+ 0, &tv);
+ if (!ui_cr_event)
+ log_print("ui_conn_reinit: timer_add_event() failed. "
+ "Connections will not be updated.");
+}
+
+/*
+ * Call the configuration API.
+ * XXX Error handling! How to do multi-line transactions? Too short arbitrary
+ * limit on the parameters?
+ */
+static void
+ui_config(char *cmd)
+{
+ char subcmd[81], section[81], tag[81], value[81], tmp[81];
+ char *v, *nv;
+ int trans = 0, items, nvlen;
+ FILE *fd;
+
+ if (sscanf(cmd, "C %80s", subcmd) != 1)
+ goto fail;
+
+ if (strcasecmp(subcmd, "get") == 0) {
+ if (sscanf(cmd, "C %*s [%80[^]]]:%80s", section, tag) != 2)
+ goto fail;
+ v = conf_get_str(section, tag);
+ fd = ui_open_result();
+ if (fd) {
+ if (v)
+ fprintf(fd, "%s\n", v);
+ fclose(fd);
+ }
+ LOG_DBG((LOG_UI, 30, "ui_config: \"%s\"", cmd));
+ return;
+ }
+
+ trans = conf_begin();
+ if (strcasecmp(subcmd, "set") == 0) {
+ items = sscanf(cmd, "C %*s [%80[^]]]:%80[^=]=%80s %80s",
+ section, tag, value, tmp);
+ if (!(items == 3 || items == 4))
+ goto fail;
+ conf_set(trans, section, tag, value, items == 4 ? 1 : 0, 0);
+ if (strcasecmp(section, "Phase 2") == 0 &&
+ (strcasecmp(tag, "Connections") == 0 ||
+ strcasecmp(tag, "Passive-connections") == 0))
+ ui_conn_reinit();
+ } else if (strcasecmp(subcmd, "add") == 0) {
+ items = sscanf(cmd, "C %*s [%80[^]]]:%80[^=]=%80s %80s",
+ section, tag, value, tmp);
+ if (!(items == 3 || items == 4))
+ goto fail;
+ v = conf_get_str(section, tag);
+ if (!v)
+ conf_set(trans, section, tag, value, 1, 0);
+ else {
+ /* Add the new value to the end of the 'v' list. */
+ nvlen = strlen(v) + strlen(value) + 2;
+ nv = (char *)malloc(nvlen);
+ if (!nv) {
+ log_error("ui_config: malloc(%d) failed",
+ nvlen);
+ if (trans)
+ conf_end(trans, 0);
+ return;
+ }
+ snprintf(nv, nvlen,
+ v[strlen(v) - 1] == ',' ? "%s%s" : "%s,%s", v,
+ value);
+ conf_set(trans, section, tag, nv, 1, 0);
+ free(nv);
+ }
+ if (strcasecmp(section, "Phase 2") == 0 &&
+ (strcasecmp(tag, "Connections") == 0 ||
+ strcasecmp(tag, "Passive-connections") == 0))
+ ui_conn_reinit();
+ } else if (strcasecmp(subcmd, "rm") == 0) {
+ if (sscanf(cmd, "C %*s [%80[^]]]:%80s", section, tag) != 2)
+ goto fail;
+ conf_remove(trans, section, tag);
+ } else if (strcasecmp(subcmd, "rms") == 0) {
+ if (sscanf(cmd, "C %*s [%80[^]]]", section) != 1)
+ goto fail;
+ conf_remove_section(trans, section);
+ } else
+ goto fail;
+
+ LOG_DBG((LOG_UI, 30, "ui_config: \"%s\"", cmd));
+ conf_end(trans, 1);
+ return;
+
+fail:
+ if (trans)
+ conf_end(trans, 0);
+ log_print("ui_config: command \"%s\" malformed", cmd);
+}
+
+static void
+ui_delete(char *cmd)
+{
+ char cookies_str[ISAKMP_HDR_COOKIES_LEN * 2 + 1];
+ char message_id_str[ISAKMP_HDR_MESSAGE_ID_LEN * 2 + 1];
+ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN];
+ u_int8_t message_id_buf[ISAKMP_HDR_MESSAGE_ID_LEN];
+ u_int8_t *message_id = message_id_buf;
+ struct sa *sa;
+
+ if (sscanf(cmd, "d %32s %8s", cookies_str, message_id_str) != 2) {
+ log_print("ui_delete: command \"%s\" malformed", cmd);
+ return;
+ }
+ if (strcmp(message_id_str, "-") == 0)
+ message_id = 0;
+
+ if (hex2raw(cookies_str, cookies, ISAKMP_HDR_COOKIES_LEN) == -1 ||
+ (message_id && hex2raw(message_id_str, message_id_buf,
+ ISAKMP_HDR_MESSAGE_ID_LEN) == -1)) {
+ log_print("ui_delete: command \"%s\" has bad arguments", cmd);
+ return;
+ }
+ sa = sa_lookup(cookies, message_id);
+ if (!sa) {
+ log_print("ui_delete: command \"%s\" found no SA", cmd);
+ return;
+ }
+ LOG_DBG((LOG_UI, 20,
+ "ui_delete: deleting SA for cookie \"%s\" msgid \"%s\"",
+ cookies_str, message_id_str));
+ sa_delete(sa, 1);
+}
+
+#ifdef USE_DEBUG
+/* Parse the debug command found in CMD. */
+static void
+ui_debug(char *cmd)
+{
+ int cls, level;
+ char subcmd[3];
+
+ if (sscanf(cmd, "D %d %d", &cls, &level) == 2) {
+ log_debug_cmd(cls, level);
+ return;
+ } else if (sscanf(cmd, "D %2s %d", subcmd, &level) == 2) {
+ switch (subcmd[0]) {
+ case 'A':
+ for (cls = 0; cls < LOG_ENDCLASS; cls++)
+ log_debug_cmd(cls, level);
+ return;
+ }
+ } else if (sscanf(cmd, "D %2s", subcmd) == 1) {
+ switch (subcmd[0]) {
+ case 'T':
+ log_debug_toggle();
+ return;
+ }
+ }
+ log_print("ui_debug: command \"%s\" malformed", cmd);
+ return;
+}
+
+static void
+ui_packetlog(char *cmd)
+{
+ char subcmd[81];
+
+ if (sscanf(cmd, "p %80s", subcmd) != 1)
+ goto fail;
+
+ if (strncasecmp(subcmd, "on=", 3) == 0) {
+ /* Start capture to a new file. */
+ if (subcmd[strlen(subcmd) - 1] == '\n')
+ subcmd[strlen(subcmd) - 1] = 0;
+ log_packet_restart(subcmd + 3);
+ } else if (strcasecmp(subcmd, "on") == 0)
+ log_packet_restart(NULL);
+ else if (strcasecmp(subcmd, "off") == 0)
+ log_packet_stop();
+ return;
+
+fail:
+ log_print("ui_packetlog: command \"%s\" malformed", cmd);
+}
+#endif /* USE_DEBUG */
+
+static void
+ui_shutdown_daemon(char *cmd)
+{
+ if (strlen(cmd) == 1) {
+ log_print("ui_shutdown_daemon: received shutdown command");
+ daemon_shutdown_now(0);
+ } else
+ log_print("ui_shutdown_daemon: command \"%s\" malformed", cmd);
+}
+
+/* Report SAs and ongoing exchanges. */
+void
+ui_report(char *cmd)
+{
+ /* XXX Skip 'cmd' as arg? */
+ sa_report();
+ exchange_report();
+ transport_report();
+ connection_report();
+ timer_report();
+ conf_report();
+}
+
+/* Report all SA configuration information. */
+void
+ui_report_sa(char *cmd)
+{
+ /* Skip 'cmd' as arg? */
+
+ FILE *fd = ui_open_result();
+ if (!fd)
+ return;
+
+ sa_report_all(fd);
+
+ fclose(fd);
+}
+
+/*
+ * Call the relevant command handler based on the first character of the
+ * line (the command).
+ */
+static void
+ui_handle_command(char *line)
+{
+ /* Find out what one-letter command was sent. */
+ switch (line[0]) {
+ case 'c':
+ ui_connect(line);
+ break;
+
+ case 'C':
+ ui_config(line);
+ break;
+
+ case 'd':
+ ui_delete(line);
+ break;
+
+#ifdef USE_DEBUG
+ case 'D':
+ ui_debug(line);
+ break;
+
+ case 'p':
+ ui_packetlog(line);
+ break;
+#endif
+
+ case 'Q':
+ ui_shutdown_daemon(line);
+ break;
+
+ case 'R':
+ reinit();
+ break;
+
+ case 'S':
+ ui_report_sa(line);
+ break;
+
+ case 'r':
+ ui_report(line);
+ break;
+
+ case 't':
+ ui_teardown(line);
+ break;
+
+ case 'T':
+ ui_teardown_all(line);
+ break;
+
+ default:
+ log_print("ui_handle_messages: unrecognized command: '%c'",
+ line[0]);
+ }
+}
+
+/*
+ * A half-complex implementation of reading from a file descriptor
+ * line by line without resorting to stdio which apparently have
+ * troubles with non-blocking fifos.
+ */
+void
+ui_handler(void)
+{
+ static char *buf = 0;
+ static char *p;
+ static size_t sz;
+ static size_t resid;
+ ssize_t n;
+ char *new_buf;
+
+ /* If no buffer, set it up. */
+ if (!buf) {
+ sz = BUF_SZ;
+ buf = malloc(sz);
+ if (!buf) {
+ log_print("ui_handler: malloc (%lu) failed",
+ (unsigned long)sz);
+ return;
+ }
+ p = buf;
+ resid = sz;
+ }
+ /* If no place left in the buffer reallocate twice as large. */
+ if (!resid) {
+ new_buf = realloc(buf, sz * 2);
+ if (!new_buf) {
+ log_print("ui_handler: realloc (%p, %lu) failed", buf,
+ (unsigned long)sz * 2);
+ free(buf);
+ buf = 0;
+ return;
+ }
+ buf = new_buf;
+ p = buf + sz;
+ resid = sz;
+ sz *= 2;
+ }
+ n = read(ui_socket, p, resid);
+ if (n == -1) {
+ log_error("ui_handler: read (%d, %p, %lu)", ui_socket, p,
+ (unsigned long)resid);
+ return;
+ }
+ if (!n)
+ return;
+ resid -= n;
+ while (n--) {
+ /*
+ * When we find a newline, cut off the line and feed it to the
+ * command processor. Then move the rest up-front.
+ */
+ if (*p == '\n') {
+ *p = '\0';
+ ui_handle_command(buf);
+ memcpy(buf, p + 1, n);
+ p = buf;
+ resid = sz - n;
+ continue;
+ }
+ p++;
+ }
+}
+
+static FILE *
+ui_open_result(void)
+{
+ FILE *fd = monitor_fopen(RESULT_FILE, "w");
+ if (!fd)
+ log_error("ui_open_result: fopen() failed");
+ return fd;
+}
diff --git a/keyexchange/isakmpd-20041012/ui.h b/keyexchange/isakmpd-20041012/ui.h
new file mode 100644
index 0000000..db9de7f
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/ui.h
@@ -0,0 +1,45 @@
+/* $OpenBSD: ui.h,v 1.7 2004/05/13 06:56:34 ho Exp $ */
+/* $EOM: ui.h,v 1.5 1998/12/01 10:20:12 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _UI_H_
+#define _UI_H_
+
+#define FIFO "/var/run/isakmpd.fifo"
+#define RESULT_FILE "/var/run/isakmpd.result"
+
+extern char *ui_fifo;
+extern int ui_socket;
+
+extern void ui_handler(void);
+extern void ui_init(void);
+extern void ui_report(char *);
+
+#endif /* _UI_H_ */
diff --git a/keyexchange/isakmpd-20041012/util.c b/keyexchange/isakmpd-20041012/util.c
new file mode 100644
index 0000000..6504cb2
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/util.c
@@ -0,0 +1,485 @@
+/* $OpenBSD: util.c,v 1.48 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: util.c,v 1.23 2000/11/23 12:22:08 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "sysdep.h"
+
+#include "log.h"
+#include "message.h"
+#include "monitor.h"
+#include "sysdep.h"
+#include "transport.h"
+#include "util.h"
+
+/*
+ * Set if -N is given, allowing name lookups to be done, possibly stalling
+ * the daemon for quite a while.
+ */
+int allow_name_lookups = 0;
+
+/*
+ * This is set to true in case of regression-test mode, when it will
+ * cause predictable random numbers be generated.
+ */
+int regrand = 0;
+
+/*
+ * If in regression-test mode, this is the seed used.
+ */
+u_long seed;
+
+/*
+ * XXX These might be turned into inlines or macros, maybe even
+ * machine-dependent ones, for performance reasons.
+ */
+u_int16_t
+decode_16(u_int8_t *cp)
+{
+ return cp[0] << 8 | cp[1];
+}
+
+u_int32_t
+decode_32(u_int8_t *cp)
+{
+ return cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3];
+}
+
+u_int64_t
+decode_64(u_int8_t *cp)
+{
+ return (u_int64_t) cp[0] << 56 | (u_int64_t) cp[1] << 48 |
+ (u_int64_t) cp[2] << 40 | (u_int64_t) cp[3] << 32 |
+ cp[4] << 24 | cp[5] << 16 | cp[6] << 8 | cp[7];
+}
+
+#if 0
+/*
+ * XXX I severly doubt that we will need this. IPv6 does not have the legacy
+ * of representation in host byte order, AFAIK.
+ */
+
+void
+decode_128(u_int8_t *cp, u_int8_t *cpp)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ int i;
+
+ for (i = 0; i < 16; i++)
+ cpp[i] = cp[15 - i];
+#elif BYTE_ORDER == BIG_ENDIAN
+ bcopy(cp, cpp, 16);
+#else
+#error "Byte order unknown!"
+#endif
+}
+#endif
+
+void
+encode_16(u_int8_t *cp, u_int16_t x)
+{
+ *cp++ = x >> 8;
+ *cp = x & 0xff;
+}
+
+void
+encode_32(u_int8_t *cp, u_int32_t x)
+{
+ *cp++ = x >> 24;
+ *cp++ = (x >> 16) & 0xff;
+ *cp++ = (x >> 8) & 0xff;
+ *cp = x & 0xff;
+}
+
+void
+encode_64(u_int8_t *cp, u_int64_t x)
+{
+ *cp++ = x >> 56;
+ *cp++ = (x >> 48) & 0xff;
+ *cp++ = (x >> 40) & 0xff;
+ *cp++ = (x >> 32) & 0xff;
+ *cp++ = (x >> 24) & 0xff;
+ *cp++ = (x >> 16) & 0xff;
+ *cp++ = (x >> 8) & 0xff;
+ *cp = x & 0xff;
+}
+
+#if 0
+/*
+ * XXX I severly doubt that we will need this. IPv6 does not have the legacy
+ * of representation in host byte order, AFAIK.
+ */
+
+void
+encode_128(u_int8_t *cp, u_int8_t *cpp)
+{
+ decode_128(cpp, cp);
+}
+#endif
+
+/* Check a buffer for all zeroes. */
+int
+zero_test(const u_int8_t *p, size_t sz)
+{
+ while (sz-- > 0)
+ if (*p++ != 0)
+ return 0;
+ return 1;
+}
+
+/* Check a buffer for all ones. */
+int
+ones_test(const u_int8_t *p, size_t sz)
+{
+ while (sz-- > 0)
+ if (*p++ != 0xff)
+ return 0;
+ return 1;
+}
+
+/*
+ * Generate a random data, len bytes long.
+ */
+u_int8_t *
+getrandom(u_int8_t *buf, size_t len)
+{
+ u_int32_t tmp = 0;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (i % sizeof tmp == 0)
+ tmp = sysdep_random();
+
+ buf[i] = tmp & 0xff;
+ tmp >>= 8;
+ }
+
+ return buf;
+}
+
+static __inline int
+hex2nibble(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+/*
+ * Convert hexadecimal string in S to raw binary buffer at BUF sized SZ
+ * bytes. Return 0 if everything is OK, -1 otherwise.
+ */
+int
+hex2raw(char *s, u_int8_t *buf, size_t sz)
+{
+ u_int8_t *bp;
+ char *p;
+ int tmp;
+
+ if (strlen(s) > sz * 2)
+ return -1;
+ for (p = s + strlen(s) - 1, bp = &buf[sz - 1]; bp >= buf; bp--) {
+ *bp = 0;
+ if (p >= s) {
+ tmp = hex2nibble(*p--);
+ if (tmp == -1)
+ return -1;
+ *bp = tmp;
+ }
+ if (p >= s) {
+ tmp = hex2nibble(*p--);
+ if (tmp == -1)
+ return -1;
+ *bp |= tmp << 4;
+ }
+ }
+ return 0;
+}
+
+int
+text2sockaddr(char *address, char *port, struct sockaddr **sa)
+{
+ struct addrinfo *ai, hints;
+
+ memset(&hints, 0, sizeof hints);
+ if (!allow_name_lookups)
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ if (getaddrinfo(address, port, &hints, &ai))
+ return -1;
+
+ *sa = malloc(sysdep_sa_len(ai->ai_addr));
+ if (!*sa) {
+ freeaddrinfo(ai);
+ return -1;
+ }
+
+ memcpy(*sa, ai->ai_addr, sysdep_sa_len(ai->ai_addr));
+ freeaddrinfo(ai);
+ return 0;
+}
+
+/*
+ * Convert a sockaddr to text. With zflag non-zero fill out with zeroes,
+ * i.e 10.0.0.10 --> "010.000.000.010"
+ */
+int
+sockaddr2text(struct sockaddr *sa, char **address, int zflag)
+{
+ char buf[NI_MAXHOST], *token, *bstart, *ep;
+ int addrlen, i, j;
+ long val;
+
+ if (getnameinfo(sa, sysdep_sa_len(sa), buf, sizeof buf, 0, 0,
+ allow_name_lookups ? 0 : NI_NUMERICHOST))
+ return -1;
+
+ if (zflag == 0) {
+ *address = strdup(buf);
+ if (!*address)
+ return -1;
+ } else
+ switch (sa->sa_family) {
+ case AF_INET:
+ addrlen = sizeof "000.000.000.000";
+ *address = malloc(addrlen);
+ if (!*address)
+ return -1;
+ buf[addrlen] = '\0';
+ bstart = buf;
+ **address = '\0';
+ while ((token = strsep(&bstart, ".")) != NULL) {
+ if (strlen(*address) > 12) {
+ free(*address);
+ return -1;
+ }
+ val = strtol(token, &ep, 10);
+ if (ep == token || val < (long)0 ||
+ val > (long)UCHAR_MAX) {
+ free(*address);
+ return -1;
+ }
+ snprintf(*address + strlen(*address),
+ addrlen - strlen(*address), "%03ld", val);
+ if (bstart)
+ strlcat(*address, ".", addrlen);
+ }
+ break;
+
+ case AF_INET6:
+ /*
+ * XXX In the algorithm below there are some magic
+ * numbers we probably could give explaining names.
+ */
+ addrlen =
+ sizeof "0000:0000:0000:0000:0000:0000:0000:0000";
+ *address = malloc(addrlen);
+ if (!*address)
+ return -1;
+
+ for (i = 0, j = 0; i < 8; i++) {
+ snprintf((*address) + j, addrlen - j,
+ "%02x%02x",
+ ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2*i],
+ ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2*i + 1]);
+ j += 4;
+ (*address)[j] =
+ (j < (addrlen - 1)) ? ':' : '\0';
+ j++;
+ }
+ break;
+
+ default:
+ *address = strdup("<error>");
+ if (!*address)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * sockaddr_addrlen and sockaddr_addrdata return the relevant sockaddr info
+ * depending on address family. Useful to keep other code shorter(/clearer?).
+ */
+int
+sockaddr_addrlen(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET6:
+ return sizeof((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
+ case AF_INET:
+ return sizeof((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ default:
+ log_print("sockaddr_addrlen: unsupported protocol family %d",
+ sa->sa_family);
+ return 0;
+ }
+}
+
+u_int8_t *
+sockaddr_addrdata(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET6:
+ return (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
+ case AF_INET:
+ return (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ default:
+ log_print("sockaddr_addrdata: unsupported protocol family %d",
+ sa->sa_family);
+ return 0;
+ }
+}
+
+in_port_t
+sockaddr_port(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET6:
+ return ((struct sockaddr_in6 *)sa)->sin6_port;
+ case AF_INET:
+ return ((struct sockaddr_in *)sa)->sin_port;
+ default:
+ log_print("sockaddr_port: unsupported protocol family %d",
+ sa->sa_family);
+ return 0;
+ }
+}
+
+/* Utility function used to set the port of a sockaddr. */
+void
+sockaddr_set_port(struct sockaddr *sa, in_port_t port)
+{
+ switch (sa->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)sa)->sin_port = htons (port);
+ break;
+
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sa)->sin6_port = htons (port);
+ break;
+ }
+}
+
+/*
+ * Convert network address to text. The network address does not need
+ * to be properly aligned.
+ */
+void
+util_ntoa(char **buf, int af, u_int8_t *addr)
+{
+ struct sockaddr_storage from;
+ struct sockaddr *sfrom = (struct sockaddr *) & from;
+ socklen_t fromlen = sizeof from;
+
+ memset(&from, 0, fromlen);
+ sfrom->sa_family = af;
+#ifndef USE_OLD_SOCKADDR
+ switch (af) {
+ case AF_INET:
+ sfrom->sa_len = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ sfrom->sa_len = sizeof(struct sockaddr_in6);
+ break;
+ }
+#endif
+ memcpy(sockaddr_addrdata(sfrom), addr, sockaddr_addrlen(sfrom));
+
+ if (sockaddr2text(sfrom, buf, 0)) {
+ log_print("util_ntoa: could not make printable address out "
+ "of sockaddr %p", sfrom);
+ *buf = 0;
+ }
+}
+
+/*
+ * Perform sanity check on files containing secret information.
+ * Returns -1 on failure, 0 otherwise.
+ * Also, if FILE_SIZE is a not a null pointer, store file size here.
+ */
+
+int
+check_file_secrecy_fd(int fd, char *name, size_t *file_size)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) == -1) {
+ log_error("check_file_secrecy: stat (\"%s\") failed", name);
+ return -1;
+ }
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ log_print("check_file_secrecy_fd: "
+ "not loading %s - file owner is not process user", name);
+ errno = EPERM;
+ return -1;
+ }
+ if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+ log_print("check_file_secrecy_fd: not loading %s - too open "
+ "permissions", name);
+ errno = EPERM;
+ return -1;
+ }
+ if (file_size)
+ *file_size = (size_t)st.st_size;
+
+ return 0;
+}
+
+/* Special for compiling with Boehms GC. See Makefile and sysdep.h */
+#if defined (USE_BOEHM_GC)
+char *
+gc_strdup(const char *x)
+{
+ char *strcpy(char *,const char *);
+ char *y = malloc(strlen(x) + 1);
+ return strcpy(y,x);
+}
+#endif
diff --git a/keyexchange/isakmpd-20041012/util.h b/keyexchange/isakmpd-20041012/util.h
new file mode 100644
index 0000000..b370ff2
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/util.h
@@ -0,0 +1,70 @@
+/* $OpenBSD: util.h,v 1.21 2004/06/23 03:01:53 hshoexer Exp $ */
+/* $EOM: util.h,v 1.10 2000/10/24 13:33:39 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2001, 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <sys/types.h>
+
+extern int allow_name_lookups;
+extern int regrand;
+extern unsigned long seed;
+
+struct message;
+struct sockaddr;
+
+extern int check_file_secrecy_fd(int, char *, size_t *);
+extern u_int16_t decode_16(u_int8_t *);
+extern u_int32_t decode_32(u_int8_t *);
+extern u_int64_t decode_64(u_int8_t *);
+#if 0
+extern void decode_128(u_int8_t *, u_int8_t *);
+#endif
+extern void encode_16(u_int8_t *, u_int16_t);
+extern void encode_32(u_int8_t *, u_int32_t);
+extern void encode_64(u_int8_t *, u_int64_t);
+#if 0
+extern void encode_128(u_int8_t *, u_int8_t *);
+#endif
+extern u_int8_t *getrandom(u_int8_t *, size_t);
+extern int hex2raw(char *, u_int8_t *, size_t);
+extern int ones_test(const u_int8_t *, size_t);
+extern int sockaddr2text(struct sockaddr *, char **, int);
+extern u_int8_t *sockaddr_addrdata(struct sockaddr *);
+extern int sockaddr_addrlen(struct sockaddr *);
+extern in_port_t sockaddr_port(struct sockaddr *);
+extern void sockaddr_set_port(struct sockaddr *, in_port_t);
+extern int text2sockaddr(char *, char *, struct sockaddr **);
+extern void util_ntoa(char **, int, u_int8_t *);
+extern int zero_test(const u_int8_t *, size_t);
+
+#endif /* _UTIL_H_ */
diff --git a/keyexchange/isakmpd-20041012/virtual.c b/keyexchange/isakmpd-20041012/virtual.c
new file mode 100644
index 0000000..d6132fe
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/virtual.c
@@ -0,0 +1,722 @@
+/* $OpenBSD: virtual.c,v 1.9 2004/09/20 21:36:50 hshoexer Exp $ */
+
+/*
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifndef linux
+#include <sys/sockio.h>
+#endif
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "conf.h"
+#include "if.h"
+#include "exchange.h"
+#include "log.h"
+#include "transport.h"
+#include "virtual.h"
+#include "udp.h"
+#include "util.h"
+
+#if defined (USE_NAT_TRAVERSAL)
+#include "udp_encap.h"
+#endif
+
+static struct transport *virtual_bind(const struct sockaddr *);
+static struct transport *virtual_bind_ADDR_ANY(sa_family_t);
+static int virtual_bind_if(char *, struct sockaddr *, void *);
+static struct transport *virtual_clone(struct transport *, struct sockaddr *);
+static struct transport *virtual_create(char *);
+static char *virtual_decode_ids (struct transport *);
+static void virtual_get_dst(struct transport *,
+ struct sockaddr **);
+static struct msg_head *virtual_get_queue(struct message *);
+static void virtual_get_src(struct transport *,
+ struct sockaddr **);
+static void virtual_handle_message(struct transport *);
+static void virtual_reinit(void);
+static void virtual_remove(struct transport *);
+static void virtual_report(struct transport *);
+static int virtual_send_message(struct message *,
+ struct transport *);
+
+static struct transport_vtbl virtual_transport_vtbl = {
+ { 0 }, "udp",
+ virtual_create,
+ virtual_reinit,
+ virtual_remove,
+ virtual_report,
+ 0,
+ 0,
+ virtual_handle_message,
+ virtual_send_message,
+ virtual_get_dst,
+ virtual_get_src,
+ virtual_decode_ids,
+ virtual_clone,
+ virtual_get_queue
+};
+
+static LIST_HEAD (virtual_listen_list, virtual_transport) virtual_listen_list;
+static struct transport *default_transport, *default_transport6;
+
+void
+virtual_init(void)
+{
+ struct conf_list *listen_on;
+
+ LIST_INIT(&virtual_listen_list);
+
+ transport_method_add(&virtual_transport_vtbl);
+
+ /* Bind the ISAKMP port(s) on all network interfaces we have. */
+ if (if_map(virtual_bind_if, 0) == -1)
+ log_fatal("virtual_init: "
+ "could not bind the ISAKMP port(s) on all interfaces");
+
+ /* Only listen to the specified address if Listen-on is configured */
+ listen_on = conf_get_list("General", "Listen-on");
+ if (listen_on) {
+ LOG_DBG((LOG_TRANSPORT, 50,
+ "virtual_init: not binding ISAKMP port(s) to ADDR_ANY"));
+ conf_free_list(listen_on);
+ return;
+ }
+
+ /*
+ * Bind to INADDR_ANY in case of new addresses popping up.
+ * Packet reception on this transport is taken as a hint to reprobe the
+ * interface list.
+ */
+ if (!bind_family || (bind_family & BIND_FAMILY_INET4)) {
+ default_transport = virtual_bind_ADDR_ANY(AF_INET);
+ if (!default_transport)
+ return;
+ LIST_INSERT_HEAD(&virtual_listen_list,
+ (struct virtual_transport *)default_transport, link);
+ transport_reference(default_transport);
+ }
+
+ if (!bind_family || (bind_family & BIND_FAMILY_INET6)) {
+ default_transport6 = virtual_bind_ADDR_ANY(AF_INET6);
+ if (!default_transport6)
+ return;
+ LIST_INSERT_HEAD(&virtual_listen_list,
+ (struct virtual_transport *)default_transport6, link);
+ transport_reference(default_transport6);
+ }
+
+ return;
+}
+
+struct virtual_transport *
+virtual_get_default(sa_family_t af)
+{
+ switch (af) {
+ case AF_INET:
+ return (struct virtual_transport *)default_transport;
+ case AF_INET6:
+ return (struct virtual_transport *)default_transport6;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Probe the interface list and determine what new interfaces have
+ * appeared.
+ *
+ * At the same time, we try to determine whether existing interfaces have
+ * been rendered invalid; we do this by marking all virtual transports before
+ * we call virtual_bind_if () through if_map (), and then releasing those
+ * transports that have not been unmarked.
+ */
+void
+virtual_reinit(void)
+{
+ struct virtual_transport *v, *v2;
+
+ /* Mark all UDP transports, except the default ones. */
+ for (v = LIST_FIRST(&virtual_listen_list); v; v = LIST_NEXT(v, link))
+ if (&v->transport != default_transport
+ && &v->transport != default_transport6)
+ v->transport.flags |= TRANSPORT_MARK;
+
+ /* Re-probe interface list. */
+ if (if_map(virtual_bind_if, 0) == -1)
+ log_print("virtual_init: "
+ "could not bind the ISAKMP port(s) on all interfaces");
+
+ /*
+ * Release listening transports for local addresses that no
+ * longer exist. virtual_bind_if () will have left those still marked.
+ */
+ v = LIST_FIRST(&virtual_listen_list);
+ while (v) {
+ v2 = LIST_NEXT(v, link);
+ if (v->transport.flags & TRANSPORT_MARK) {
+ LIST_REMOVE(v, link);
+ transport_release(&v->transport);
+ }
+ v = v2;
+ }
+}
+
+struct virtual_transport *
+virtual_listen_lookup(struct sockaddr *addr)
+{
+ struct virtual_transport *v;
+ struct udp_transport *u;
+
+ for (v = LIST_FIRST(&virtual_listen_list); v;
+ v = LIST_NEXT(v, link)) {
+ if (!(u = (struct udp_transport *)v->main))
+ if (!(u = (struct udp_transport *)v->encap)) {
+ log_print("virtual_listen_lookup: "
+ "virtual %p has no low-level transports",
+ v);
+ continue;
+ }
+
+ if (u->src->sa_family == addr->sa_family
+ && sockaddr_addrlen(u->src) == sockaddr_addrlen(addr)
+ && memcmp(sockaddr_addrdata (u->src),
+ sockaddr_addrdata(addr),
+ sockaddr_addrlen(addr)) == 0)
+ return v;
+ }
+
+ LOG_DBG((LOG_TRANSPORT, 40, "virtual_listen_lookup: no match"));
+ return 0;
+}
+
+/*
+ * Initialize an object of the VIRTUAL transport class.
+ */
+static struct transport *
+virtual_bind(const struct sockaddr *addr)
+{
+ struct virtual_transport *v;
+ struct sockaddr_storage tmp_sa;
+ char *port;
+ char *ep;
+ long lport;
+
+ v = (struct virtual_transport *)calloc(1, sizeof *v);
+ if (!v) {
+ log_error("virtual_bind: calloc(1, %lu) failed",
+ (unsigned long)sizeof *v);
+ return 0;
+ }
+
+ v->transport.vtbl = &virtual_transport_vtbl;
+
+ memcpy(&tmp_sa, addr, sysdep_sa_len((struct sockaddr *)addr));
+
+ /*
+ * Get port.
+ * XXX Use getservbyname too.
+ */
+ port = udp_default_port ? udp_default_port : UDP_DEFAULT_PORT_STR;
+ lport = strtol(port, &ep, 10);
+ if (*ep != '\0' || lport < 0 || lport > (long)USHRT_MAX) {
+ log_print("virtual_bind: "
+ "port string \"%s\" not convertible to in_port_t", port);
+ free(v);
+ return 0;
+ }
+
+ sockaddr_set_port((struct sockaddr *)&tmp_sa, (in_port_t)lport);
+ v->main = udp_bind((struct sockaddr *)&tmp_sa);
+ if (!v->main) {
+ free(v);
+ return 0;
+ }
+ ((struct transport *)v->main)->virtual = (struct transport *)v;
+
+#if defined (USE_NAT_TRAVERSAL)
+ memcpy(&tmp_sa, addr, sysdep_sa_len((struct sockaddr *)addr));
+
+ /*
+ * Get port.
+ * XXX Use getservbyname too.
+ */
+ port = udp_encap_default_port
+ ? udp_encap_default_port : UDP_ENCAP_DEFAULT_PORT_STR;
+ lport = strtol(port, &ep, 10);
+ if (*ep != '\0' || lport < 0 || lport > (long)USHRT_MAX) {
+ log_print("virtual_bind: "
+ "port string \"%s\" not convertible to in_port_t", port);
+ v->main->vtbl->remove(v->main);
+ free(v);
+ return 0;
+ }
+
+ sockaddr_set_port((struct sockaddr *)&tmp_sa, (in_port_t)lport);
+ v->encap = udp_encap_bind((struct sockaddr *)&tmp_sa);
+ if (!v->encap) {
+ v->main->vtbl->remove(v->main);
+ free(v);
+ return 0;
+ }
+ ((struct transport *)v->encap)->virtual = (struct transport *)v;
+#endif
+ v->encap_is_active = 0;
+
+ transport_setup(&v->transport, 1);
+ v->transport.flags |= TRANSPORT_LISTEN;
+
+ return (struct transport *)v;
+}
+
+static struct transport *
+virtual_bind_ADDR_ANY(sa_family_t af)
+{
+ struct sockaddr_storage dflt_stor;
+ struct sockaddr_in *d4 = (struct sockaddr_in *)&dflt_stor;
+ struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)&dflt_stor;
+ struct transport *t;
+ struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+
+ memset(&dflt_stor, 0, sizeof dflt_stor);
+ switch (af) {
+ case AF_INET:
+ d4->sin_family = af;
+#if !defined (LINUX_IPSEC)
+ d4->sin_len = sizeof(struct sockaddr_in);
+#endif
+ d4->sin_addr.s_addr = INADDR_ANY;
+ break;
+
+ case AF_INET6:
+ d6->sin6_family = af;
+#if !defined (LINUX_IPSEC)
+ d6->sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ memcpy(&d6->sin6_addr.s6_addr, &in6addr_any,
+ sizeof in6addr_any);
+ break;
+ }
+
+ t = virtual_bind((struct sockaddr *)&dflt_stor);
+ if (!t)
+ log_error("virtual_bind_ADDR_ANY: "
+ "could not allocate default IPv%s ISAKMP port(s)",
+ af == AF_INET ? "4" : "6");
+ return t;
+}
+
+static int
+virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg)
+{
+ struct conf_list *listen_on;
+ struct virtual_transport *v;
+ struct conf_list_node *address;
+ struct sockaddr *addr;
+ struct transport *t;
+ struct ifreq flags_ifr;
+ char *addr_str;
+ int s, error;
+
+#if defined (USE_DEBUG)
+ if (sockaddr2text(if_addr, &addr_str, 0))
+ addr_str = 0;
+
+ LOG_DBG((LOG_TRANSPORT, 90,
+ "virtual_bind_if: interface %s family %s address %s",
+ ifname ? ifname : "<unknown>",
+ if_addr->sa_family == AF_INET ? "v4" :
+ (if_addr->sa_family == AF_INET6 ? "v6" : "<unknown>"),
+ addr_str ? addr_str : "<invalid>"));
+ if (addr_str)
+ free(addr_str);
+#endif
+
+ /*
+ * Drop non-Internet stuff.
+ */
+ if ((if_addr->sa_family != AF_INET
+ || sysdep_sa_len(if_addr) != sizeof (struct sockaddr_in))
+ && (if_addr->sa_family != AF_INET6
+ || sysdep_sa_len(if_addr) != sizeof (struct sockaddr_in6)))
+ return 0;
+
+ /*
+ * Only create sockets for families we should listen to.
+ */
+ if (bind_family)
+ switch (if_addr->sa_family) {
+ case AF_INET:
+ if ((bind_family & BIND_FAMILY_INET4) == 0)
+ return 0;
+ break;
+ case AF_INET6:
+ if ((bind_family & BIND_FAMILY_INET6) == 0)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ /*
+ * These special addresses are not useable as they have special meaning
+ * in the IP stack.
+ */
+ if (if_addr->sa_family == AF_INET
+ && (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_ANY
+ || (((struct sockaddr_in *)if_addr)->sin_addr.s_addr
+ == INADDR_NONE)))
+ return 0;
+
+ /*
+ * Go through the list of transports and see if we already have this
+ * address bound. If so, unmark the transport and skip it; this allows
+ * us to call this function when we suspect a new address has appeared.
+ */
+ if ((v = virtual_listen_lookup(if_addr)) != 0) {
+ LOG_DBG ((LOG_TRANSPORT, 90, "virtual_bind_if: "
+ "already bound"));
+ v->transport.flags &= ~TRANSPORT_MARK;
+ return 0;
+ }
+
+ /*
+ * Don't bother with interfaces that are down.
+ * Note: This socket is only used to collect the interface status.
+ */
+ s = socket(if_addr->sa_family, SOCK_DGRAM, 0);
+ if (s == -1) {
+ log_error("virtual_bind_if: "
+ "socket (%d, SOCK_DGRAM, 0) failed", if_addr->sa_family);
+ return -1;
+ }
+ strlcpy(flags_ifr.ifr_name, ifname, sizeof flags_ifr.ifr_name);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&flags_ifr) == -1) {
+ log_error("virtual_bind_if: "
+ "ioctl (%d, SIOCGIFFLAGS, ...) failed", s);
+ close(s);
+ return -1;
+ }
+ close(s);
+ if (!(flags_ifr.ifr_flags & IFF_UP))
+ return 0;
+
+ /* Set the port number to zero. */
+ switch (if_addr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)if_addr)->sin_port = htons(0);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)if_addr)->sin6_port = htons(0);
+ break;
+ default:
+ log_print("virtual_bind_if: unsupported protocol family %d",
+ if_addr->sa_family);
+ break;
+ }
+
+ /*
+ * If we are explicit about what addresses we can listen to, be sure
+ * to respect that option.
+ * This is quite wasteful redoing the list-run for every interface,
+ * but who cares? This is not an operation that needs to be fast.
+ */
+ listen_on = conf_get_list("General", "Listen-on");
+ if (listen_on) {
+ for (address = TAILQ_FIRST(&listen_on->fields); address;
+ address = TAILQ_NEXT(address, link)) {
+ if (text2sockaddr(address->field, 0, &addr)) {
+ log_print("virtual_bind_if: "
+ "invalid address %s in \"Listen-on\"",
+ address->field);
+ continue;
+ }
+
+ /* If found, take the easy way out. */
+ if (memcmp(addr, if_addr,
+ sysdep_sa_len(addr)) == 0) {
+ free(addr);
+ break;
+ }
+ free(addr);
+ }
+ conf_free_list(listen_on);
+
+ /*
+ * If address is zero then we did not find the address among
+ * the ones we should listen to.
+ * XXX We do not discover if we do not find our listen
+ * addresses. Maybe this should be the other way round.
+ */
+ if (!address)
+ return 0;
+ }
+
+ t = virtual_bind(if_addr);
+ if (!t) {
+ error = sockaddr2text(if_addr, &addr_str, 0);
+ log_print("virtual_bind_if: failed to create a socket on %s",
+ error ? "unknown" : addr_str);
+ if (!error)
+ free(addr_str);
+ return -1;
+ }
+ LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)t,
+ link);
+ transport_reference(t);
+ return 0;
+}
+
+static struct transport *
+virtual_clone(struct transport *vt, struct sockaddr *raddr)
+{
+ struct virtual_transport *v = (struct virtual_transport *)vt;
+ struct virtual_transport *v2;
+ struct transport *t;
+
+ t = malloc(sizeof *v);
+ if (!t) {
+ log_error("virtual_clone: malloc(%lu) failed",
+ (unsigned long)sizeof *v);
+ return 0;
+ }
+ v2 = (struct virtual_transport *)t;
+
+ memcpy(v2, v, sizeof *v);
+ /* Remove the copy's links into virtual_listen_list. */
+ v2->link.le_next = 0;
+ v2->link.le_prev = 0;
+
+ if (v->encap_is_active)
+ v2->main = 0; /* No need to clone this. */
+ else {
+ v2->main = v->main->vtbl->clone(v->main, raddr);
+ v2->main->virtual = (struct transport *)v2;
+ }
+#if defined (USE_NAT_TRAVERSAL)
+ /* XXX fix strtol() call */
+ sockaddr_set_port(raddr, udp_encap_default_port ?
+ strtol(udp_encap_default_port, NULL, 10) : UDP_ENCAP_DEFAULT_PORT);
+ v2->encap = v->encap->vtbl->clone(v->encap, raddr);
+ v2->encap->virtual = (struct transport *)v2;
+#endif
+ LOG_DBG((LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)",
+ v, t, v->encap_is_active ? "encap" : "main",
+ v->encap_is_active ? v2->encap : v2->main));
+
+ t->flags &= ~TRANSPORT_LISTEN;
+ transport_setup(t, 1);
+ return t;
+}
+
+static struct transport *
+virtual_create(char *name)
+{
+ struct virtual_transport *v;
+ struct transport *t, *t2;
+
+ t = transport_create("udp_physical", name);
+ if (!t)
+ return 0;
+
+#if defined (USE_NAT_TRAVERSAL)
+ t2 = transport_create("udp_encap", name);
+ if (!t2) {
+ t->vtbl->remove(t);
+ return 0;
+ }
+#else
+ t2 = 0;
+#endif
+
+ v = (struct virtual_transport *)calloc(1, sizeof *v);
+ if (!v) {
+ log_error("virtual_create: calloc(1, %lu) failed",
+ (unsigned long)sizeof *v);
+ t->vtbl->remove(t);
+ if (t2)
+ t2->vtbl->remove(t2);
+ return 0;
+ }
+
+ memcpy(v, t, sizeof *t);
+ v->transport.virtual = 0;
+ v->main = t;
+ v->encap = t2;
+ v->transport.vtbl = &virtual_transport_vtbl;
+ t->virtual = (struct transport *)v;
+ if (t2)
+ t2->virtual = (struct transport *)v;
+ transport_setup(&v->transport, 1);
+ return (struct transport *)v;
+}
+
+static void
+virtual_remove(struct transport *t)
+{
+ struct virtual_transport *v = (struct virtual_transport *)t;
+
+ if (v->encap)
+ v->encap->vtbl->remove(v->encap);
+ if (v->main)
+ v->main->vtbl->remove(v->main);
+ if (v->link.le_prev)
+ LIST_REMOVE(v, link);
+
+ LOG_DBG((LOG_TRANSPORT, 90, "virtual_remove: removed %p", v));
+ free(t);
+}
+
+static void
+virtual_report(struct transport *t)
+{
+ return;
+}
+
+static void
+virtual_handle_message(struct transport *t)
+{
+ if (t->virtual == default_transport ||
+ t->virtual == default_transport6) {
+ /* XXX drain pending message. See udp_handle_message(). */
+
+ virtual_reinit();
+
+ /*
+ * As we don't know the actual destination address of the
+ * packet, we can't really deal with it. So, just ignore it
+ * and hope we catch the retransmission.
+ */
+ return;
+ }
+
+ /*
+ * As per the NAT-T draft, in case we have already switched ports,
+ * any messages recieved on the old (500) port SHOULD be discarded.
+ * (Actually, while phase 1 messages should be discarded,
+ * informational exchanges MAY be processed normally. For now, we
+ * discard them all.)
+ */
+ if (((struct virtual_transport *)t->virtual)->encap_is_active &&
+ ((struct virtual_transport *)t->virtual)->main == t) {
+ LOG_DBG((LOG_MESSAGE, 10, "virtual_handle_message: "
+ "message on old port discarded"));
+ return;
+ }
+
+ t->vtbl->handle_message(t);
+}
+
+static int
+virtual_send_message(struct message *msg, struct transport *t)
+{
+ struct virtual_transport *v =
+ (struct virtual_transport *)msg->transport;
+#if defined (USE_NAT_TRAVERSAL)
+ struct sockaddr *dst;
+ in_port_t port;
+
+ /*
+ * Activate NAT-T Encapsulation if
+ * - the exchange says we can, and
+ * - in ID_PROT, after step 4 (draft-ietf-ipsec-nat-t-ike-03), or
+ * - in other exchange (Aggressive, ), asap
+ * XXX ISAKMP_EXCH_BASE etc?
+ */
+ if (v->encap_is_active == 0 &&
+ (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) &&
+ (msg->exchange->type != ISAKMP_EXCH_ID_PROT ||
+ msg->exchange->step > 4)) {
+ LOG_DBG((LOG_MESSAGE, 10, "virtual_send_message: "
+ "enabling NAT-T encapsulation for this exchange"));
+ v->encap_is_active++;
+
+ /* Copy destination port if it is translated (NAT). */
+ v->main->vtbl->get_dst(v->main, &dst);
+ port = ntohs(sockaddr_port(dst));
+ if (port != UDP_DEFAULT_PORT) {
+ v->main->vtbl->get_dst(v->encap, &dst);
+ sockaddr_set_port(dst, port);
+ }
+ }
+#endif /* USE_NAT_TRAVERSAL */
+
+ if (v->encap_is_active)
+ return v->encap->vtbl->send_message(msg, v->encap);
+ else
+ return v->main->vtbl->send_message(msg, v->main);
+}
+
+static void
+virtual_get_src(struct transport *t, struct sockaddr **s)
+{
+ struct virtual_transport *v = (struct virtual_transport *)t;
+
+ if (v->encap_is_active)
+ v->encap->vtbl->get_src(v->encap, s);
+ else
+ v->main->vtbl->get_src(v->main, s);
+}
+
+static void
+virtual_get_dst(struct transport *t, struct sockaddr **s)
+{
+ struct virtual_transport *v = (struct virtual_transport *)t;
+
+ if (v->encap_is_active)
+ v->encap->vtbl->get_dst(v->encap, s);
+ else
+ v->main->vtbl->get_dst(v->main, s);
+}
+
+static char *
+virtual_decode_ids(struct transport *t)
+{
+ struct virtual_transport *v = (struct virtual_transport *)t;
+
+ if (v->encap_is_active)
+ return v->encap->vtbl->decode_ids(t);
+ else
+ return v->main->vtbl->decode_ids(t);
+}
+
+static struct msg_head *
+virtual_get_queue(struct message *msg)
+{
+ if (msg->flags & MSG_PRIORITIZED)
+ return &msg->transport->prio_sendq;
+ else
+ return &msg->transport->sendq;
+}
diff --git a/keyexchange/isakmpd-20041012/virtual.h b/keyexchange/isakmpd-20041012/virtual.h
new file mode 100644
index 0000000..7a3bd21
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/virtual.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: virtual.h,v 1.1 2004/06/20 15:24:05 ho Exp $ */
+
+/*
+ * Copyright (c) 2004 Håkan Olsson. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#ifndef _TRP_VIRTUAL_H_
+#define _TRP_VIRTUAL_H_
+
+struct virtual_transport {
+ struct transport transport;
+ struct transport *main; /* Normally this transport is used. */
+ struct transport *encap; /* Or this, depending on 'encap_is_active'. */
+ int encap_is_active;
+ LIST_ENTRY (virtual_transport) link;
+};
+
+void virtual_init(void);
+struct virtual_transport *virtual_get_default(sa_family_t);
+struct virtual_transport *virtual_listen_lookup(struct sockaddr *);
+
+#endif /* _TRP_VIRTUAL_H_ */
diff --git a/keyexchange/isakmpd-20041012/x509.c b/keyexchange/isakmpd-20041012/x509.c
new file mode 100644
index 0000000..0897557
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/x509.c
@@ -0,0 +1,1439 @@
+/* $OpenBSD: x509.c,v 1.95 2004/08/10 19:21:01 deraadt Exp $ */
+/* $EOM: x509.c,v 1.54 2001/01/16 18:42:16 ho Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifdef USE_X509
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef USE_POLICY
+#include <regex.h>
+#include <keynote.h>
+#endif /* USE_POLICY */
+
+#include "sysdep.h"
+
+#include "cert.h"
+#include "conf.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "ipsec.h"
+#include "log.h"
+#include "math_mp.h"
+#include "monitor.h"
+#include "policy.h"
+#include "sa.h"
+#include "util.h"
+#include "x509.h"
+
+static u_int16_t x509_hash(u_int8_t *, size_t);
+static void x509_hash_init(void);
+static X509 *x509_hash_find(u_int8_t *, size_t);
+static int x509_hash_enter(X509 *);
+
+/*
+ * X509_STOREs do not support subjectAltNames, so we have to build
+ * our own hash table.
+ */
+
+/*
+ * XXX Actually this store is not really useful, we never use it as we have
+ * our own hash table. It also gets collisons if we have several certificates
+ * only differing in subjectAltName.
+ */
+static X509_STORE *x509_certs = 0;
+static X509_STORE *x509_cas = 0;
+
+/* Initial number of bits used as hash. */
+#define INITIAL_BUCKET_BITS 6
+
+struct x509_hash {
+ LIST_ENTRY(x509_hash) link;
+
+ X509 *cert;
+};
+
+static LIST_HEAD(x509_list, x509_hash) *x509_tab = 0;
+
+/* Works both as a maximum index and a mask. */
+static int bucket_mask;
+
+#ifdef USE_POLICY
+/*
+ * Given an X509 certificate, create a KeyNote assertion where
+ * Issuer/Subject -> Authorizer/Licensees.
+ * XXX RSA-specific.
+ */
+int
+x509_generate_kn(int id, X509 *cert)
+{
+ char *fmt = "Authorizer: \"rsa-hex:%s\"\nLicensees: \"rsa-hex:%s"
+ "\"\nConditions: %s >= \"%s\" && %s <= \"%s\";\n";
+ char *ikey, *skey, *buf, isname[256], subname[256];
+ char *fmt2 = "Authorizer: \"DN:%s\"\nLicensees: \"DN:%s\"\n"
+ "Conditions: %s >= \"%s\" && %s <= \"%s\";\n";
+ X509_NAME *issuer, *subject;
+ struct keynote_deckey dc;
+ X509_STORE_CTX csc;
+ X509_OBJECT obj;
+ X509 *icert;
+ RSA *key;
+ time_t tt;
+ char before[15], after[15], *timecomp, *timecomp2;
+ ASN1_TIME *tm;
+ int i, buf_len;
+
+ LOG_DBG((LOG_POLICY, 90,
+ "x509_generate_kn: generating KeyNote policy for certificate %p",
+ cert));
+
+ issuer = X509_get_issuer_name(cert);
+ subject = X509_get_subject_name(cert);
+
+ /* Missing or self-signed, ignore cert but don't report failure. */
+ if (!issuer || !subject || !X509_name_cmp(issuer, subject))
+ return 1;
+
+ if (!x509_cert_get_key(cert, &key)) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: failed to get public key from cert"));
+ return 0;
+ }
+ dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
+ dc.dec_key = key;
+ ikey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX,
+ KEYNOTE_PUBLIC_KEY);
+ if (keynote_errno == ERROR_MEMORY) {
+ log_print("x509_generate_kn: failed to get memory for "
+ "public key");
+ RSA_free(key);
+ LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "
+ "subject key"));
+ return 0;
+ }
+ if (!ikey) {
+ RSA_free(key);
+ LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "
+ "subject key"));
+ return 0;
+ }
+ RSA_free(key);
+
+ /* Now find issuer's certificate so we can get the public key. */
+ X509_STORE_CTX_init(&csc, x509_cas, cert, NULL);
+ if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj) !=
+ X509_LU_X509) {
+ X509_STORE_CTX_cleanup(&csc);
+ X509_STORE_CTX_init(&csc, x509_certs, cert, NULL);
+ if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj)
+ != X509_LU_X509) {
+ X509_STORE_CTX_cleanup(&csc);
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: no certificate found for "
+ "issuer"));
+ return 0;
+ }
+ }
+ X509_STORE_CTX_cleanup(&csc);
+ icert = obj.data.x509;
+
+ if (icert == NULL) {
+ LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: "
+ "missing certificates, cannot construct X509 chain"));
+ free(ikey);
+ return 0;
+ }
+ if (!x509_cert_get_key(icert, &key)) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: failed to get public key from cert"));
+ free(ikey);
+ return 0;
+ }
+ X509_OBJECT_free_contents(&obj);
+
+ dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
+ dc.dec_key = key;
+ skey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX,
+ KEYNOTE_PUBLIC_KEY);
+ if (keynote_errno == ERROR_MEMORY) {
+ log_error("x509_generate_kn: failed to get memory for public "
+ "key");
+ free(ikey);
+ RSA_free(key);
+ LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
+ "key"));
+ return 0;
+ }
+ if (!skey) {
+ free(ikey);
+ RSA_free(key);
+ LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
+ "key"));
+ return 0;
+ }
+ RSA_free(key);
+
+ buf_len = strlen(fmt) + strlen(ikey) + strlen(skey) + 56;
+ buf = calloc(buf_len, sizeof(char));
+ buf_len *= sizeof(char);
+ if (!buf) {
+ log_error("x509_generate_kn: "
+ "failed to allocate memory for KeyNote credential");
+ free(ikey);
+ free(skey);
+ return 0;
+ }
+ if (((tm = X509_get_notBefore(cert)) == NULL) ||
+ (tm->type != V_ASN1_UTCTIME &&
+ tm->type != V_ASN1_GENERALIZEDTIME)) {
+ tt = time(0);
+ strftime(before, 14, "%Y%m%d%H%M%S", localtime(&tt));
+ timecomp = "LocalTimeOfDay";
+ } else {
+ if (tm->data[tm->length - 1] == 'Z') {
+ timecomp = "GMTTimeOfDay";
+ i = tm->length - 2;
+ } else {
+ timecomp = "LocalTimeOfDay";
+ i = tm->length - 1;
+ }
+
+ for (; i >= 0; i--) {
+ if (tm->data[i] < '0' || tm->data[i] > '9') {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid data in "
+ "NotValidBefore time field"));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ }
+
+ if (tm->type == V_ASN1_UTCTIME) {
+ if ((tm->length < 10) || (tm->length > 13)) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid length "
+ "of NotValidBefore time field (%d)",
+ tm->length));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ /* Validity checks. */
+ if ((tm->data[2] != '0' && tm->data[2] != '1') ||
+ (tm->data[2] == '0' && tm->data[3] == '0') ||
+ (tm->data[2] == '1' && tm->data[3] > '2') ||
+ (tm->data[4] > '3') ||
+ (tm->data[4] == '0' && tm->data[5] == '0') ||
+ (tm->data[4] == '3' && tm->data[5] > '1') ||
+ (tm->data[6] > '2') ||
+ (tm->data[6] == '2' && tm->data[7] > '3') ||
+ (tm->data[8] > '5')) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid value in "
+ "NotValidBefore time field"));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ /* Stupid UTC tricks. */
+ if (tm->data[0] < '5')
+ snprintf(before, sizeof before, "20%s",
+ tm->data);
+ else
+ snprintf(before, sizeof before, "19%s",
+ tm->data);
+ } else { /* V_ASN1_GENERICTIME */
+ if ((tm->length < 12) || (tm->length > 15)) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid length of "
+ "NotValidBefore time field (%d)",
+ tm->length));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ /* Validity checks. */
+ if ((tm->data[4] != '0' && tm->data[4] != '1') ||
+ (tm->data[4] == '0' && tm->data[5] == '0') ||
+ (tm->data[4] == '1' && tm->data[5] > '2') ||
+ (tm->data[6] > '3') ||
+ (tm->data[6] == '0' && tm->data[7] == '0') ||
+ (tm->data[6] == '3' && tm->data[7] > '1') ||
+ (tm->data[8] > '2') ||
+ (tm->data[8] == '2' && tm->data[9] > '3') ||
+ (tm->data[10] > '5')) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid value in "
+ "NotValidBefore time field"));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ snprintf(before, sizeof before, "%s", tm->data);
+ }
+
+ /* Fix missing seconds. */
+ if (tm->length < 12) {
+ before[12] = '0';
+ before[13] = '0';
+ }
+ /* This will overwrite trailing 'Z'. */
+ before[14] = '\0';
+ }
+
+ tm = X509_get_notAfter(cert);
+ if (tm == NULL &&
+ (tm->type != V_ASN1_UTCTIME &&
+ tm->type != V_ASN1_GENERALIZEDTIME)) {
+ tt = time(0);
+ strftime(after, 14, "%Y%m%d%H%M%S", localtime(&tt));
+ timecomp2 = "LocalTimeOfDay";
+ } else {
+ if (tm->data[tm->length - 1] == 'Z') {
+ timecomp2 = "GMTTimeOfDay";
+ i = tm->length - 2;
+ } else {
+ timecomp2 = "LocalTimeOfDay";
+ i = tm->length - 1;
+ }
+
+ for (; i >= 0; i--) {
+ if (tm->data[i] < '0' || tm->data[i] > '9') {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid data in "
+ "NotValidAfter time field"));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ }
+
+ if (tm->type == V_ASN1_UTCTIME) {
+ if ((tm->length < 10) || (tm->length > 13)) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid length of "
+ "NotValidAfter time field (%d)",
+ tm->length));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ /* Validity checks. */
+ if ((tm->data[2] != '0' && tm->data[2] != '1') ||
+ (tm->data[2] == '0' && tm->data[3] == '0') ||
+ (tm->data[2] == '1' && tm->data[3] > '2') ||
+ (tm->data[4] > '3') ||
+ (tm->data[4] == '0' && tm->data[5] == '0') ||
+ (tm->data[4] == '3' && tm->data[5] > '1') ||
+ (tm->data[6] > '2') ||
+ (tm->data[6] == '2' && tm->data[7] > '3') ||
+ (tm->data[8] > '5')) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid value in "
+ "NotValidAfter time field"));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ /* Stupid UTC tricks. */
+ if (tm->data[0] < '5')
+ snprintf(after, sizeof after, "20%s",
+ tm->data);
+ else
+ snprintf(after, sizeof after, "19%s",
+ tm->data);
+ } else { /* V_ASN1_GENERICTIME */
+ if ((tm->length < 12) || (tm->length > 15)) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid length of "
+ "NotValidAfter time field (%d)",
+ tm->length));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ /* Validity checks. */
+ if ((tm->data[4] != '0' && tm->data[4] != '1') ||
+ (tm->data[4] == '0' && tm->data[5] == '0') ||
+ (tm->data[4] == '1' && tm->data[5] > '2') ||
+ (tm->data[6] > '3') ||
+ (tm->data[6] == '0' && tm->data[7] == '0') ||
+ (tm->data[6] == '3' && tm->data[7] > '1') ||
+ (tm->data[8] > '2') ||
+ (tm->data[8] == '2' && tm->data[9] > '3') ||
+ (tm->data[10] > '5')) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: invalid value in "
+ "NotValidAfter time field"));
+ free(ikey);
+ free(skey);
+ free(buf);
+ return 0;
+ }
+ snprintf(after, sizeof after, "%s", tm->data);
+ }
+
+ /* Fix missing seconds. */
+ if (tm->length < 12) {
+ after[12] = '0';
+ after[13] = '0';
+ }
+ after[14] = '\0'; /* This will overwrite trailing 'Z' */
+ }
+
+ snprintf(buf, buf_len, fmt, skey, ikey, timecomp, before, timecomp2,
+ after);
+ free(ikey);
+ free(skey);
+
+ if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: failed to add new KeyNote credential"));
+ free(buf);
+ return 0;
+ }
+ /* We could print the assertion here, but log_print() truncates... */
+ LOG_DBG((LOG_POLICY, 60, "x509_generate_kn: added credential"));
+
+ free(buf);
+
+ if (!X509_NAME_oneline(issuer, isname, 256)) {
+ LOG_DBG((LOG_POLICY, 50,
+ "x509_generate_kn: "
+ "X509_NAME_oneline (issuer, ...) failed"));
+ return 0;
+ }
+ if (!X509_NAME_oneline(subject, subname, 256)) {
+ LOG_DBG((LOG_POLICY, 50,
+ "x509_generate_kn: "
+ "X509_NAME_oneline (subject, ...) failed"));
+ return 0;
+ }
+ buf_len = strlen(fmt2) + strlen(isname) + strlen(subname) + 56;
+ buf = malloc(buf_len);
+ if (!buf) {
+ log_error("x509_generate_kn: malloc (%d) failed", buf_len);
+ return 0;
+ }
+ snprintf(buf, buf_len, fmt2, isname, subname, timecomp, before,
+ timecomp2, after);
+
+ if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) {
+ LOG_DBG((LOG_POLICY, 30,
+ "x509_generate_kn: failed to add new KeyNote credential"));
+ free(buf);
+ return 0;
+ }
+ LOG_DBG((LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s",
+ buf));
+
+ free(buf);
+ return 1;
+}
+#endif /* USE_POLICY */
+
+static u_int16_t
+x509_hash(u_int8_t *id, size_t len)
+{
+ u_int16_t bucket = 0;
+ size_t i;
+
+ /* XXX We might resize if we are crossing a certain threshold. */
+ for (i = 4; i < (len & ~1); i += 2) {
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= (id[i] + 1) * (id[i + 1] + 257);
+ }
+ /* Hash in the last character of odd length IDs too. */
+ if (i < len)
+ bucket ^= (id[i] + 1) * (id[i] + 257);
+
+ bucket &= bucket_mask;
+ return bucket;
+}
+
+static void
+x509_hash_init(void)
+{
+ struct x509_hash *certh;
+ int i;
+
+ bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1;
+
+ /* If reinitializing, free existing entries. */
+ if (x509_tab) {
+ for (i = 0; i <= bucket_mask; i++)
+ for (certh = LIST_FIRST(&x509_tab[i]); certh;
+ certh = LIST_FIRST(&x509_tab[i])) {
+ LIST_REMOVE(certh, link);
+ free(certh);
+ }
+ free(x509_tab);
+ }
+ x509_tab = malloc((bucket_mask + 1) * sizeof(struct x509_list));
+ if (!x509_tab)
+ log_fatal("x509_hash_init: malloc (%lu) failed",
+ (bucket_mask + 1) *
+ (unsigned long)sizeof(struct x509_list));
+ for (i = 0; i <= bucket_mask; i++) {
+ LIST_INIT(&x509_tab[i]);
+ }
+}
+
+/* Lookup a certificate by an ID blob. */
+static X509 *
+x509_hash_find(u_int8_t *id, size_t len)
+{
+ struct x509_hash *cert;
+ u_int8_t **cid;
+ u_int32_t *clen;
+ int n, i, id_found;
+
+ for (cert = LIST_FIRST(&x509_tab[x509_hash(id, len)]); cert;
+ cert = LIST_NEXT(cert, link)) {
+ if (!x509_cert_get_subjects(cert->cert, &n, &cid, &clen))
+ continue;
+
+ id_found = 0;
+ for (i = 0; i < n; i++) {
+ LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", id, len));
+ LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", cid[i],
+ clen[i]));
+ /*
+ * XXX This identity predicate needs to be
+ * understood.
+ */
+ if (clen[i] == len && id[0] == cid[i][0] &&
+ memcmp(id + 4, cid[i] + 4, len - 4) == 0) {
+ id_found++;
+ break;
+ }
+ }
+ cert_free_subjects(n, cid, clen);
+ if (!id_found)
+ continue;
+
+ LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: return X509 %p",
+ cert->cert));
+ return cert->cert;
+ }
+
+ LOG_DBG((LOG_CRYPTO, 70,
+ "x509_hash_find: no certificate matched query"));
+ return 0;
+}
+
+static int
+x509_hash_enter(X509 *cert)
+{
+ u_int16_t bucket = 0;
+ u_int8_t **id;
+ u_int32_t *len;
+ struct x509_hash *certh;
+ int n, i;
+
+ if (!x509_cert_get_subjects(cert, &n, &id, &len)) {
+ log_print("x509_hash_enter: cannot retrieve subjects");
+ return 0;
+ }
+ for (i = 0; i < n; i++) {
+ certh = calloc(1, sizeof *certh);
+ if (!certh) {
+ cert_free_subjects(n, id, len);
+ log_error("x509_hash_enter: calloc (1, %lu) failed",
+ (unsigned long)sizeof *certh);
+ return 0;
+ }
+ certh->cert = cert;
+
+ bucket = x509_hash(id[i], len[i]);
+
+ LIST_INSERT_HEAD(&x509_tab[bucket], certh, link);
+ LOG_DBG((LOG_CRYPTO, 70,
+ "x509_hash_enter: cert %p added to bucket %d",
+ cert, bucket));
+ }
+ cert_free_subjects(n, id, len);
+
+ return 1;
+}
+
+/* X509 Certificate Handling functions. */
+
+int
+x509_read_from_dir(X509_STORE *ctx, char *name, int hash)
+{
+ struct dirent *file;
+#if defined (USE_PRIVSEP)
+ struct monitor_dirents *dir;
+#else
+ DIR *dir;
+#endif
+ FILE *certfp;
+ X509 *cert;
+ struct stat sb;
+ char fullname[PATH_MAX];
+ int fd, off, size;
+
+ if (strlen(name) >= sizeof fullname - 1) {
+ log_print("x509_read_from_dir: directory name too long");
+ return 0;
+ }
+ LOG_DBG((LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s",
+ name));
+
+ dir = monitor_opendir(name);
+ if (!dir) {
+ LOG_DBG((LOG_CRYPTO, 10,
+ "x509_read_from_dir: opendir (\"%s\") failed: %s",
+ name, strerror(errno)));
+ return 0;
+ }
+ strlcpy(fullname, name, sizeof fullname);
+ off = strlen(fullname);
+ size = sizeof fullname - off;
+
+ while ((file = monitor_readdir(dir)) != NULL) {
+ strlcpy(fullname + off, file->d_name, size);
+
+ if (file->d_type != DT_UNKNOWN) {
+ if (file->d_type != DT_REG && file->d_type != DT_LNK)
+ continue;
+ }
+
+ LOG_DBG((LOG_CRYPTO, 60,
+ "x509_read_from_dir: reading certificate %s",
+ file->d_name));
+
+ if ((fd = monitor_open(fullname, O_RDONLY, 0)) == -1) {
+ log_error("x509_read_from_dir: monitor_open"
+ "(\"%s\", O_RDONLY, 0) failed", fullname);
+ continue;
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ log_error("x509_read_from_dir: fstat failed");
+ close(fd);
+ continue;
+ }
+
+ if (!(sb.st_mode & S_IFREG)) {
+ close(fd);
+ continue;
+ }
+
+ if ((certfp = fdopen(fd, "r")) == NULL) {
+ log_error("x509_read_from_dir: fdopen failed");
+ close(fd);
+ continue;
+ }
+
+#if SSLEAY_VERSION_NUMBER >= 0x00904100L
+ cert = PEM_read_X509(certfp, NULL, NULL, NULL);
+#else
+ cert = PEM_read_X509(certfp, NULL, NULL);
+#endif
+ fclose(certfp);
+
+ if (cert == NULL) {
+ log_print("x509_read_from_dir: PEM_read_bio_X509 "
+ "failed for %s", file->d_name);
+ continue;
+ }
+ if (!X509_STORE_add_cert(ctx, cert)) {
+ /*
+ * This is actually expected if we have several
+ * certificates only differing in subjectAltName,
+ * which is not an something that is strange.
+ * Consider multi-homed machines.
+ */
+ LOG_DBG((LOG_CRYPTO, 50,
+ "x509_read_from_dir: X509_STORE_add_cert failed "
+ "for %s", file->d_name));
+ }
+ if (hash)
+ if (!x509_hash_enter(cert))
+ log_print("x509_read_from_dir: "
+ "x509_hash_enter (%s) failed",
+ file->d_name);
+ }
+
+ monitor_closedir(dir);
+
+ return 1;
+}
+
+/* XXX share code with x509_read_from_dir() ? */
+int
+x509_read_crls_from_dir(X509_STORE *ctx, char *name)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ struct dirent *file;
+#if defined (USE_PRIVSEP)
+ struct monitor_dirents *dir;
+#else
+ DIR *dir;
+#endif
+ FILE *crlfp;
+ X509_CRL *crl;
+ struct stat sb;
+ char fullname[PATH_MAX];
+ int fd, off, size;
+
+ if (strlen(name) >= sizeof fullname - 1) {
+ log_print("x509_read_crls_from_dir: directory name too long");
+ return 0;
+ }
+ LOG_DBG((LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs "
+ "from %s", name));
+
+ dir = monitor_opendir(name);
+ if (!dir) {
+ LOG_DBG((LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir "
+ "(\"%s\") failed: %s", name, strerror(errno)));
+ return 0;
+ }
+ strlcpy(fullname, name, sizeof fullname);
+ off = strlen(fullname);
+ size = sizeof fullname - off;
+
+ while ((file = monitor_readdir(dir)) != NULL) {
+ strlcpy(fullname + off, file->d_name, size);
+
+ if (file->d_type != DT_UNKNOWN) {
+ if (file->d_type != DT_REG && file->d_type != DT_LNK)
+ continue;
+ }
+
+ LOG_DBG((LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading "
+ "CRL %s", file->d_name));
+
+ if ((fd = monitor_open(fullname, O_RDONLY, 0)) == -1) {
+ log_error("x509_read_crls_from_dir: monitor_open"
+ "(\"%s\", O_RDONLY, 0) failed", fullname);
+ continue;
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ log_error("x509_read_crls_from_dir: fstat failed");
+ close(fd);
+ continue;
+ }
+
+ if (!(sb.st_mode & S_IFREG)) {
+ close(fd);
+ continue;
+ }
+
+ if ((crlfp = fdopen(fd, "r")) == NULL) {
+ log_error("x509_read_crls_from_dir: fdopen failed");
+ close(fd);
+ continue;
+ }
+
+ crl = PEM_read_X509_CRL(crlfp, NULL, NULL, NULL);
+
+ fclose(crlfp);
+
+ if (crl == NULL) {
+ log_print("x509_read_crls_from_dir: "
+ "PEM_read_X509_CRL failed for %s",
+ file->d_name);
+ continue;
+ }
+ if (!X509_STORE_add_crl(ctx, crl)) {
+ LOG_DBG((LOG_CRYPTO, 50, "x509_read_crls_from_dir: "
+ "X509_STORE_add_crl failed for %s", file->d_name));
+ continue;
+ }
+ /*
+ * XXX This is to make x509_cert_validate set this (and
+ * XXX another) flag when validating certificates. Currently,
+ * XXX OpenSSL defaults to reject an otherwise valid
+ * XXX certificate (chain) if these flags are set but there
+ * XXX are no CRLs to check. The current workaround is to only
+ * XXX set the flags if we actually loaded some CRL data.
+ */
+ X509_STORE_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
+ }
+
+ monitor_closedir(dir);
+#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L */
+
+ return 1;
+}
+
+/* Initialize our databases and load our own certificates. */
+int
+x509_cert_init(void)
+{
+ char *dirname;
+
+ x509_hash_init();
+
+ /* Process CA certificates we will trust. */
+ dirname = conf_get_str("X509-certificates", "CA-directory");
+ if (!dirname) {
+ log_print("x509_cert_init: no CA-directory");
+ return 0;
+ }
+ /* Free if already initialized. */
+ if (x509_cas)
+ X509_STORE_free(x509_cas);
+
+ x509_cas = X509_STORE_new();
+ if (!x509_cas) {
+ log_print("x509_cert_init: creating new X509_STORE failed");
+ return 0;
+ }
+ if (!x509_read_from_dir(x509_cas, dirname, 0)) {
+ log_print("x509_cert_init: x509_read_from_dir failed");
+ return 0;
+ }
+ /* Process client certificates we will accept. */
+ dirname = conf_get_str("X509-certificates", "Cert-directory");
+ if (!dirname) {
+ log_print("x509_cert_init: no Cert-directory");
+ return 0;
+ }
+ /* Free if already initialized. */
+ if (x509_certs)
+ X509_STORE_free(x509_certs);
+
+ x509_certs = X509_STORE_new();
+ if (!x509_certs) {
+ log_print("x509_cert_init: creating new X509_STORE failed");
+ return 0;
+ }
+ if (!x509_read_from_dir(x509_certs, dirname, 1)) {
+ log_print("x509_cert_init: x509_read_from_dir failed");
+ return 0;
+ }
+ return 1;
+}
+
+int
+x509_crl_init(void)
+{
+ /*
+ * XXX I'm not sure if the method to use CRLs in certificate validation
+ * is valid for OpenSSL versions prior to 0.9.7. For now, simply do not
+ * support it.
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ char *dirname;
+ dirname = conf_get_str("X509-certificates", "CRL-directory");
+ if (!dirname) {
+ log_print("x509_crl_init: no CRL-directory");
+ return 0;
+ }
+ if (!x509_read_crls_from_dir(x509_cas, dirname)) {
+ LOG_DBG((LOG_MISC, 10,
+ "x509_crl_init: x509_read_crls_from_dir failed"));
+ return 0;
+ }
+#else
+ LOG_DBG((LOG_CRYPTO, 10, "x509_crl_init: CRL support only "
+ "with OpenSSL v0.9.7 or later"));
+#endif
+
+ return 1;
+}
+
+void *
+x509_cert_get(u_int8_t *asn, u_int32_t len)
+{
+ return x509_from_asn(asn, len);
+}
+
+int
+x509_cert_validate(void *scert)
+{
+ X509_STORE_CTX csc;
+ X509_NAME *issuer, *subject;
+ X509 *cert = (X509 *) scert;
+ EVP_PKEY *key;
+ int res, err;
+
+ /*
+ * Validate the peer certificate by checking with the CA certificates
+ * we trust.
+ */
+ X509_STORE_CTX_init(&csc, x509_cas, cert, NULL);
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ /* XXX See comment in x509_read_crls_from_dir. */
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+ if (x509_cas->param->flags & X509_V_FLAG_CRL_CHECK) {
+#else
+ if (x509_cas->flags & X509_V_FLAG_CRL_CHECK) {
+#endif
+ X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_CRL_CHECK);
+ X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_CRL_CHECK_ALL);
+ }
+#endif
+ res = X509_verify_cert(&csc);
+ err = csc.error;
+ X509_STORE_CTX_cleanup(&csc);
+
+ /*
+ * Return if validation succeeded or self-signed certs are not
+ * accepted.
+ *
+ * XXX X509_verify_cert seems to return -1 if the validation should be
+ * retried somehow. We take this as an error and give up.
+ */
+ if (res > 0)
+ return 1;
+ else if (res < 0 ||
+ (res == 0 && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) {
+ if (err)
+ log_print("x509_cert_validate: %.100s",
+ X509_verify_cert_error_string(err));
+ return 0;
+ } else if (!conf_get_str("X509-certificates", "Accept-self-signed")) {
+ if (err)
+ log_print("x509_cert_validate: %.100s",
+ X509_verify_cert_error_string(err));
+ return 0;
+ }
+ issuer = X509_get_issuer_name(cert);
+ subject = X509_get_subject_name(cert);
+
+ if (!issuer || !subject || X509_name_cmp(issuer, subject))
+ return 0;
+
+ key = X509_get_pubkey(cert);
+ if (!key) {
+ log_print("x509_cert_validate: could not get public key from "
+ "self-signed cert");
+ return 0;
+ }
+ if (X509_verify(cert, key) == -1) {
+ log_print("x509_cert_validate: self-signed cert is bad");
+ return 0;
+ }
+ return 1;
+}
+
+int
+x509_cert_insert(int id, void *scert)
+{
+ X509 *cert;
+ int res;
+
+ cert = X509_dup((X509 *)scert);
+ if (!cert) {
+ log_print("x509_cert_insert: X509_dup failed");
+ return 0;
+ }
+#ifdef USE_POLICY
+ if (x509_generate_kn(id, cert) == 0) {
+ LOG_DBG((LOG_POLICY, 50,
+ "x509_cert_insert: x509_generate_kn failed"));
+ X509_free(cert);
+ return 0;
+ }
+#endif /* USE_POLICY */
+
+ res = x509_hash_enter(cert);
+ if (!res)
+ X509_free(cert);
+
+ return res;
+}
+
+static struct x509_hash *
+x509_hash_lookup(X509 *cert)
+{
+ struct x509_hash *certh;
+ int i;
+
+ for (i = 0; i <= bucket_mask; i++)
+ for (certh = LIST_FIRST(&x509_tab[i]); certh;
+ certh = LIST_NEXT(certh, link))
+ if (certh->cert == cert)
+ return certh;
+ return 0;
+}
+
+void
+x509_cert_free(void *cert)
+{
+ struct x509_hash *certh = x509_hash_lookup((X509 *) cert);
+
+ if (certh)
+ LIST_REMOVE(certh, link);
+ X509_free((X509 *) cert);
+}
+
+/* Validate the BER Encoding of a RDNSequence in the CERT_REQ payload. */
+int
+x509_certreq_validate(u_int8_t *asn, u_int32_t len)
+{
+ int res = 1;
+#if 0
+ struct norm_type name = SEQOF("issuer", RDNSequence);
+
+ if (!asn_template_clone(&name, 1) ||
+ (asn = asn_decode_sequence(asn, len, &name)) == 0) {
+ log_print("x509_certreq_validate: can not decode 'acceptable "
+ "CA' info");
+ res = 0;
+ }
+ asn_free(&name);
+#endif
+
+ /* XXX - not supported directly in SSL - later. */
+
+ return res;
+}
+
+/* Decode the BER Encoding of a RDNSequence in the CERT_REQ payload. */
+void *
+x509_certreq_decode(u_int8_t *asn, u_int32_t len)
+{
+#if 0
+ /* XXX This needs to be done later. */
+ struct norm_type aca = SEQOF("aca", RDNSequence);
+ struct norm_type *tmp;
+ struct x509_aca naca, *ret;
+
+ if (!asn_template_clone(&aca, 1) ||
+ (asn = asn_decode_sequence(asn, len, &aca)) == 0) {
+ log_print("x509_certreq_decode: can not decode 'acceptable "
+ "CA' info");
+ goto fail;
+ }
+ memset(&naca, 0, sizeof(naca));
+
+ tmp = asn_decompose("aca.RelativeDistinguishedName."
+ "AttributeValueAssertion", &aca);
+ if (!tmp)
+ goto fail;
+ x509_get_attribval(tmp, &naca.name1);
+
+ tmp = asn_decompose("aca.RelativeDistinguishedName[1]"
+ ".AttributeValueAssertion", &aca);
+ if (tmp)
+ x509_get_attribval(tmp, &naca.name2);
+
+ asn_free(&aca);
+
+ ret = malloc(sizeof(struct x509_aca));
+ if (ret)
+ memcpy(ret, &naca, sizeof(struct x509_aca));
+ else {
+ log_error("x509_certreq_decode: malloc (%lu) failed",
+ (unsigned long) sizeof(struct x509_aca));
+ x509_free_aca(&aca);
+ }
+
+ return ret;
+
+fail:
+ asn_free(&aca);
+#endif
+ return 0;
+}
+
+void
+x509_free_aca(void *blob)
+{
+ struct x509_aca *aca = blob;
+
+ if (aca->name1.type)
+ free(aca->name1.type);
+ if (aca->name1.val)
+ free(aca->name1.val);
+
+ if (aca->name2.type)
+ free(aca->name2.type);
+ if (aca->name2.val)
+ free(aca->name2.val);
+}
+
+X509 *
+x509_from_asn(u_char *asn, u_int len)
+{
+ BIO *certh;
+ X509 *scert = 0;
+
+ certh = BIO_new(BIO_s_mem());
+ if (!certh) {
+ log_error("x509_from_asn: BIO_new (BIO_s_mem ()) failed");
+ return 0;
+ }
+ if (BIO_write(certh, asn, len) == -1) {
+ log_error("x509_from_asn: BIO_write failed\n");
+ goto end;
+ }
+ scert = d2i_X509_bio(certh, NULL);
+ if (!scert) {
+ log_print("x509_from_asn: d2i_X509_bio failed\n");
+ goto end;
+ }
+end:
+ BIO_free(certh);
+ return scert;
+}
+
+/*
+ * Obtain a certificate from an acceptable CA.
+ * XXX We don't check if the certificate we find is from an accepted CA.
+ */
+int
+x509_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert,
+ u_int32_t *certlen)
+{
+ struct x509_aca *aca = data;
+ X509 *scert;
+
+ if (aca)
+ LOG_DBG((LOG_CRYPTO, 60, "x509_cert_obtain: "
+ "acceptable certificate authorities here"));
+
+ /* We need our ID to find a certificate. */
+ if (!id) {
+ log_print("x509_cert_obtain: ID is missing");
+ return 0;
+ }
+ scert = x509_hash_find(id, id_len);
+ if (!scert)
+ return 0;
+
+ x509_serialize(scert, cert, certlen);
+ if (!*cert)
+ return 0;
+ return 1;
+}
+
+/* Returns a pointer to the subjectAltName information of X509 certificate. */
+int
+x509_cert_subjectaltname(X509 *scert, u_int8_t **altname, u_int32_t *len)
+{
+ X509_EXTENSION *subjectaltname;
+ u_int8_t *sandata;
+ int extpos, santype, sanlen;
+
+ extpos = X509_get_ext_by_NID(scert, NID_subject_alt_name, -1);
+ if (extpos == -1) {
+ log_print("x509_cert_subjectaltname: "
+ "certificate does not contain subjectAltName");
+ return 0;
+ }
+ subjectaltname = X509_get_ext(scert, extpos);
+
+ if (!subjectaltname || !subjectaltname->value ||
+ !subjectaltname->value->data ||
+ subjectaltname->value->length < 4) {
+ log_print("x509_cert_subjectaltname: invalid "
+ "subjectaltname extension");
+ return 0;
+ }
+ /* SSL does not handle unknown ASN stuff well, do it by hand. */
+ sandata = subjectaltname->value->data;
+ santype = sandata[2] & 0x3f;
+ sanlen = sandata[3];
+ sandata += 4;
+
+ if (sanlen + 4 != subjectaltname->value->length) {
+ log_print("x509_cert_subjectaltname: subjectaltname invalid "
+ "length");
+ return 0;
+ }
+ *len = sanlen;
+ *altname = sandata;
+ return santype;
+}
+
+int
+x509_cert_get_subjects(void *scert, int *cnt, u_int8_t ***id,
+ u_int32_t **id_len)
+{
+ X509 *cert = scert;
+ X509_NAME *subject;
+ int type;
+ u_int8_t *altname;
+ u_int32_t altlen;
+ u_int8_t *buf = 0;
+ unsigned char *ubuf;
+ int i;
+
+ *id = 0;
+ *id_len = 0;
+
+ /*
+ * XXX There can be a collection of subjectAltNames, but for now I
+ * only return the subjectName and a single subjectAltName, if
+ * present.
+ */
+ type = x509_cert_subjectaltname(cert, &altname, &altlen);
+ if (!type) {
+ *cnt = 1;
+ altlen = 0;
+ } else
+ *cnt = 2;
+
+ *id = calloc(*cnt, sizeof **id);
+ if (!*id) {
+ log_print("x509_cert_get_subject: malloc (%lu) failed",
+ *cnt * (unsigned long)sizeof **id);
+ goto fail;
+ }
+ *id_len = malloc(*cnt * sizeof **id_len);
+ if (!*id_len) {
+ log_print("x509_cert_get_subject: malloc (%lu) failed",
+ *cnt * (unsigned long)sizeof **id_len);
+ goto fail;
+ }
+ /* Stash the subjectName into the first slot. */
+ subject = X509_get_subject_name(cert);
+ if (!subject)
+ goto fail;
+
+ (*id_len)[0] =
+ ISAKMP_ID_DATA_OFF + i2d_X509_NAME(subject, NULL) -
+ ISAKMP_GEN_SZ;
+ (*id)[0] = malloc((*id_len)[0]);
+ if (!(*id)[0]) {
+ log_print("x509_cert_get_subject: malloc (%d) failed",
+ (*id_len)[0]);
+ goto fail;
+ }
+ SET_ISAKMP_ID_TYPE((*id)[0] - ISAKMP_GEN_SZ, IPSEC_ID_DER_ASN1_DN);
+ ubuf = (*id)[0] + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+ i2d_X509_NAME(subject, &ubuf);
+
+ if (altlen) {
+ /* Stash the subjectAltName into the second slot. */
+ buf = malloc(altlen + ISAKMP_ID_DATA_OFF);
+ if (!buf) {
+ log_print("x509_cert_get_subject: malloc (%d) failed",
+ altlen + ISAKMP_ID_DATA_OFF);
+ goto fail;
+ }
+ switch (type) {
+ case X509v3_DNS_NAME:
+ SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_FQDN);
+ break;
+
+ case X509v3_RFC_NAME:
+ SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_USER_FQDN);
+ break;
+
+ case X509v3_IP_ADDR:
+ /*
+ * XXX I dislike the numeric constants, but I don't
+ * know what we should use otherwise.
+ */
+ switch (altlen) {
+ case 4:
+ SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR);
+ break;
+
+ case 16:
+ SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR);
+ break;
+
+ default:
+ log_print("x509_cert_get_subject: invalid "
+ "subjectAltName IPaddress length %d ",
+ altlen);
+ goto fail;
+ }
+ break;
+ }
+
+ SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0);
+ SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0);
+ memcpy(buf + ISAKMP_ID_DATA_OFF, altname, altlen);
+
+ (*id_len)[1] = ISAKMP_ID_DATA_OFF + altlen - ISAKMP_GEN_SZ;
+ (*id)[1] = malloc((*id_len)[1]);
+ if (!(*id)[1]) {
+ log_print("x509_cert_get_subject: malloc (%d) failed",
+ (*id_len)[1]);
+ goto fail;
+ }
+ memcpy((*id)[1], buf + ISAKMP_GEN_SZ, (*id_len)[1]);
+
+ free(buf);
+ buf = 0;
+ }
+ return 1;
+
+fail:
+ for (i = 0; i < *cnt; i++)
+ if ((*id)[i])
+ free((*id)[i]);
+ if (*id)
+ free(*id);
+ if (*id_len)
+ free(*id_len);
+ if (buf)
+ free(buf);
+ return 0;
+}
+
+int
+x509_cert_get_key(void *scert, void *keyp)
+{
+ X509 *cert = scert;
+ EVP_PKEY *key;
+
+ key = X509_get_pubkey(cert);
+
+ /* Check if we got the right key type. */
+ if (key->type != EVP_PKEY_RSA) {
+ log_print("x509_cert_get_key: public key is not a RSA key");
+ X509_free(cert);
+ return 0;
+ }
+ *(RSA **)keyp = RSAPublicKey_dup(key->pkey.rsa);
+
+ return *(RSA **)keyp == NULL ? 0 : 1;
+}
+
+void *
+x509_cert_dup(void *scert)
+{
+ return X509_dup(scert);
+}
+
+void
+x509_serialize(void *scert, u_int8_t **data, u_int32_t *datalen)
+{
+ u_int8_t *p;
+
+ *datalen = i2d_X509((X509 *)scert, NULL);
+ *data = p = malloc(*datalen);
+ if (!p) {
+ log_error("x509_serialize: malloc (%d) failed", *datalen);
+ return;
+ }
+ *datalen = i2d_X509((X509 *)scert, &p);
+}
+
+/* From cert to printable */
+char *
+x509_printable(void *cert)
+{
+ char *s;
+ u_int8_t *data;
+ u_int32_t datalen, i;
+
+ x509_serialize(cert, &data, &datalen);
+ if (!data)
+ return 0;
+
+ s = malloc(datalen * 2 + 1);
+ if (!s) {
+ free(data);
+ log_error("x509_printable: malloc (%d) failed",
+ datalen * 2 + 1);
+ return 0;
+ }
+ for (i = 0; i < datalen; i++)
+ snprintf(s + (2 * i), 2 * (datalen - i) + 1, "%02x", data[i]);
+ free(data);
+ return s;
+}
+
+/* From printable to cert */
+void *
+x509_from_printable(char *cert)
+{
+ u_int8_t *buf;
+ int plen, ret;
+ void *foo;
+
+ plen = (strlen(cert) + 1) / 2;
+ buf = malloc(plen);
+ if (!buf) {
+ log_error("x509_from_printable: malloc (%d) failed", plen);
+ return 0;
+ }
+ ret = hex2raw(cert, buf, plen);
+ if (ret == -1) {
+ free(buf);
+ log_print("x509_from_printable: badly formatted cert");
+ return 0;
+ }
+ foo = x509_cert_get(buf, plen);
+ free(buf);
+ if (!foo)
+ log_print("x509_from_printable: "
+ "could not retrieve certificate");
+ return foo;
+}
+
+char *
+x509_DN_string(u_int8_t *asn1, size_t sz)
+{
+ X509_NAME *name;
+ u_int8_t *p = asn1;
+ char buf[256]; /* XXX Just a guess at a maximum length. */
+
+ name = d2i_X509_NAME(NULL, &p, sz);
+ if (!name) {
+ log_print("x509_DN_string: d2i_X509_NAME failed");
+ return 0;
+ }
+ if (!X509_NAME_oneline(name, buf, sizeof buf - 1)) {
+ log_print("x509_DN_string: X509_NAME_oneline failed");
+ X509_NAME_free(name);
+ return 0;
+ }
+ X509_NAME_free(name);
+ buf[sizeof buf - 1] = '\0';
+ return strdup(buf);
+}
+#endif /* USE_X509 */
diff --git a/keyexchange/isakmpd-20041012/x509.h b/keyexchange/isakmpd-20041012/x509.h
new file mode 100644
index 0000000..adba74e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/x509.h
@@ -0,0 +1,90 @@
+/* $OpenBSD: x509.h,v 1.21 2004/05/23 18:17:56 hshoexer Exp $ */
+/* $EOM: x509.h,v 1.11 2000/09/28 12:53:27 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999 Niels Provos. All rights reserved.
+ * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2000, 2001 Niklas Hallqvist. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _X509_H_
+#define _X509_H_
+
+#include "libcrypto.h"
+
+#define X509v3_RFC_NAME 1
+#define X509v3_DNS_NAME 2
+#define X509v3_IP_ADDR 7
+
+struct x509_attribval {
+ char *type;
+ char *val;
+};
+
+/*
+ * The acceptable certification authority.
+ * XXX We only support two names at the moment, as of ASN this can
+ * be dynamic but we don't care for now.
+ */
+struct x509_aca {
+ struct x509_attribval name1;
+ struct x509_attribval name2;
+};
+
+struct X509;
+struct X509_STORE;
+
+/* Functions provided by cert handler. */
+
+int x509_certreq_validate(u_int8_t *, u_int32_t);
+void *x509_certreq_decode(u_int8_t *, u_int32_t);
+void x509_cert_free(void *);
+void *x509_cert_get(u_int8_t *, u_int32_t);
+int x509_cert_get_key(void *, void *);
+int x509_cert_get_subjects(void *, int *, u_int8_t ***, u_int32_t **);
+int x509_cert_init(void);
+int x509_crl_init(void);
+int x509_cert_obtain(u_int8_t *, size_t, void *, u_int8_t **,
+ u_int32_t *);
+int x509_cert_validate(void *);
+void x509_free_aca(void *);
+void *x509_cert_dup(void *);
+void x509_serialize(void *, u_int8_t **, u_int32_t *);
+char *x509_printable(void *);
+void *x509_from_printable(char *);
+
+/* Misc. X509 certificate functions. */
+
+char *x509_DN_string(u_int8_t *, size_t);
+int x509_cert_insert(int, void *);
+int x509_cert_subjectaltname(X509 * cert, u_char **, u_int *);
+X509 *x509_from_asn(u_char *, u_int);
+int x509_generate_kn(int, X509 *);
+int x509_read_from_dir(X509_STORE *, char *, int);
+int x509_read_crls_from_dir(X509_STORE *, char *);
+
+#endif /* _X509_H_ */
diff --git a/keyexchange/isakmpd-20041012/x509v3.cnf b/keyexchange/isakmpd-20041012/x509v3.cnf
new file mode 100644
index 0000000..1e98444
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/x509v3.cnf
@@ -0,0 +1,26 @@
+# default settings
+CERTPATHLEN = 1
+CERTUSAGE = digitalSignature,keyCertSign
+CERTIP = 0.0.0.0
+CERTFQDN = nohost.nodomain
+
+# This section should be referenced when building an x509v3 CA
+# Certificate.
+# The default path length and the key usage can be overriden
+# modified by setting the CERTPATHLEN and CERTUSAGE environment
+# variables.
+[x509v3_CA]
+basicConstraints=critical,CA:true,pathlen:$ENV::CERTPATHLEN
+keyUsage=$ENV::CERTUSAGE
+
+# This section should be referenced to add an IP Address
+# as an alternate subject name, needed by isakmpd
+# The address must be provided in the CERTIP environment variable
+[x509v3_IPAddr]
+subjectAltName=IP:$ENV::CERTIP
+
+# This section should be referenced to add a FQDN hostname
+# as an alternate subject name, needed by isakmpd
+# The address must be provided in the CERTFQDN environment variable
+[x509v3_FQDN]
+subjectAltName=DNS:$ENV::CERTFQDN