From fff4b74db26968bac72ade4bd6c702be7b51ec7a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 15 May 2012 16:59:00 +0200 Subject: Bye bye Pluto! Charon will take over IKEv1 duties from here. This also removes libfreeswan and whack. --- src/Makefile.am | 8 +- src/checksum/Makefile.am | 5 - src/libfreeswan/Android.mk | 38 - src/libfreeswan/Makefile.am | 22 - src/libfreeswan/addrtoa.c | 66 - src/libfreeswan/addrtot.c | 302 -- src/libfreeswan/addrtypeof.c | 94 - src/libfreeswan/anyaddr.3 | 86 - src/libfreeswan/anyaddr.c | 147 - src/libfreeswan/atoaddr.3 | 291 -- src/libfreeswan/atoaddr.c | 261 - src/libfreeswan/atoasr.3 | 185 - src/libfreeswan/atoasr.c | 210 - src/libfreeswan/atosubnet.c | 214 - src/libfreeswan/atoul.3 | 160 - src/libfreeswan/atoul.c | 88 - src/libfreeswan/copyright.c | 57 - src/libfreeswan/datatot.c | 230 - src/libfreeswan/freeswan.h | 371 -- src/libfreeswan/goodmask.3 | 56 - src/libfreeswan/goodmask.c | 95 - src/libfreeswan/initaddr.3 | 128 - src/libfreeswan/initaddr.c | 51 - src/libfreeswan/initsaid.c | 31 - src/libfreeswan/initsubnet.3 | 136 - src/libfreeswan/initsubnet.c | 93 - src/libfreeswan/internal.h | 46 - src/libfreeswan/ipsec_param.h | 54 - src/libfreeswan/pfkey.h | 205 - src/libfreeswan/pfkey_v2_build.c | 1388 ----- src/libfreeswan/pfkey_v2_debug.c | 104 - src/libfreeswan/pfkey_v2_ext_bits.c | 692 --- src/libfreeswan/pfkey_v2_parse.c | 1539 ------ src/libfreeswan/pfkeyv2.h | 368 -- src/libfreeswan/portof.3 | 69 - src/libfreeswan/portof.c | 96 - src/libfreeswan/rangetoa.c | 59 - src/libfreeswan/rangetosubnet.3 | 58 - src/libfreeswan/rangetosubnet.c | 224 - src/libfreeswan/sameaddr.3 | 164 - src/libfreeswan/sameaddr.c | 188 - src/libfreeswan/satot.c | 132 - src/libfreeswan/subnetof.3 | 46 - src/libfreeswan/subnetof.c | 58 - src/libfreeswan/subnettoa.c | 60 - src/libfreeswan/subnettot.c | 54 - src/libfreeswan/subnettypeof.c | 107 - src/libfreeswan/ttoaddr.3 | 374 -- src/libfreeswan/ttoaddr.c | 471 -- src/libfreeswan/ttodata.3 | 280 - src/libfreeswan/ttodata.c | 720 --- src/libfreeswan/ttoprotoport.c | 101 - src/libfreeswan/ttosa.3 | 287 -- src/libfreeswan/ttosa.c | 280 - src/libfreeswan/ttosubnet.c | 296 -- src/libfreeswan/ttoul.3 | 191 - src/libfreeswan/ttoul.c | 89 - src/libfreeswan/ultoa.c | 65 - src/libfreeswan/ultot.c | 81 - src/pluto/.gitignore | 2 - src/pluto/Android.mk | 80 - src/pluto/Makefile.am | 155 - src/pluto/ac.c | 298 -- src/pluto/ac.h | 39 - src/pluto/adns.c | 610 --- src/pluto/adns.h | 78 - src/pluto/alg_info.c | 683 --- src/pluto/alg_info.h | 80 - src/pluto/builder.c | 150 - src/pluto/builder.h | 24 - src/pluto/ca.c | 712 --- src/pluto/ca.h | 58 - src/pluto/certs.c | 268 - src/pluto/certs.h | 80 - src/pluto/connections.c | 4507 ---------------- src/pluto/connections.h | 366 -- src/pluto/constants.c | 1401 ----- src/pluto/constants.h | 1099 ---- src/pluto/cookie.c | 73 - src/pluto/cookie.h | 22 - src/pluto/crl.c | 541 -- src/pluto/crl.h | 53 - src/pluto/crypto.c | 698 --- src/pluto/crypto.h | 64 - src/pluto/db_ops.c | 412 -- src/pluto/db_ops.h | 54 - src/pluto/defs.c | 145 - src/pluto/defs.h | 79 - src/pluto/demux.c | 2527 --------- src/pluto/demux.h | 97 - src/pluto/dnskey.c | 1590 ------ src/pluto/dnskey.h | 75 - src/pluto/event_queue.c | 195 - src/pluto/event_queue.h | 69 - src/pluto/fetch.c | 766 --- src/pluto/fetch.h | 82 - src/pluto/foodgroups.c | 450 -- src/pluto/foodgroups.h | 22 - src/pluto/ike_alg.c | 452 -- src/pluto/ike_alg.h | 76 - src/pluto/ipsec_doi.c | 5921 ---------------------- src/pluto/ipsec_doi.h | 108 - src/pluto/kameipsec.h | 47 - src/pluto/kernel.c | 2114 -------- src/pluto/kernel.h | 118 - src/pluto/kernel_alg.c | 663 --- src/pluto/kernel_alg.h | 43 - src/pluto/kernel_pfkey.c | 380 -- src/pluto/kernel_pfkey.h | 20 - src/pluto/keys.c | 1474 ------ src/pluto/keys.h | 93 - src/pluto/lex.c | 211 - src/pluto/lex.h | 50 - src/pluto/log.c | 946 ---- src/pluto/log.h | 234 - src/pluto/modecfg.c | 1263 ----- src/pluto/modecfg.h | 78 - src/pluto/myid.c | 121 - src/pluto/myid.h | 38 - src/pluto/nat_traversal.c | 845 --- src/pluto/nat_traversal.h | 152 - src/pluto/ocsp.c | 1558 ------ src/pluto/ocsp.h | 85 - src/pluto/packet.c | 1242 ----- src/pluto/packet.h | 653 --- src/pluto/pkcs7.c | 755 --- src/pluto/pkcs7.h | 53 - src/pluto/plugin_list.c | 72 - src/pluto/plugin_list.h | 21 - src/pluto/plugins/xauth/Makefile.am | 15 - src/pluto/plugins/xauth/xauth_default_provider.c | 66 - src/pluto/plugins/xauth/xauth_default_provider.h | 33 - src/pluto/plugins/xauth/xauth_default_verifier.c | 81 - src/pluto/plugins/xauth/xauth_default_verifier.h | 33 - src/pluto/plugins/xauth/xauth_plugin.c | 54 - src/pluto/plugins/xauth/xauth_plugin.h | 42 - src/pluto/pluto.8 | 1594 ------ src/pluto/pluto.c | 73 - src/pluto/pluto.h | 76 - src/pluto/plutomain.c | 852 ---- src/pluto/rcv_whack.c | 728 --- src/pluto/rcv_whack.h | 15 - src/pluto/routing.txt | 329 -- src/pluto/rsaref/pkcs11.h | 299 -- src/pluto/rsaref/pkcs11f.h | 912 ---- src/pluto/rsaref/pkcs11t.h | 1685 ------ src/pluto/rsaref/unix.h | 24 - src/pluto/server.c | 910 ---- src/pluto/server.h | 56 - src/pluto/smartcard.c | 1940 ------- src/pluto/smartcard.h | 100 - src/pluto/spdb.c | 2315 --------- src/pluto/spdb.h | 110 - src/pluto/state.c | 952 ---- src/pluto/state.h | 274 - src/pluto/timer.c | 551 -- src/pluto/timer.h | 34 - src/pluto/vendor.c | 511 -- src/pluto/vendor.h | 137 - src/pluto/virtual.c | 325 -- src/pluto/virtual.h | 29 - src/pluto/whack_attribute.c | 365 -- src/pluto/whack_attribute.h | 111 - src/pluto/x509.c | 463 -- src/pluto/x509.h | 42 - src/pluto/xauth/xauth_manager.c | 127 - src/pluto/xauth/xauth_manager.h | 80 - src/pluto/xauth/xauth_provider.h | 56 - src/pluto/xauth/xauth_verifier.h | 56 - src/starter/Android.mk | 4 - src/starter/Makefile.am | 4 - src/starter/confread.c | 12 +- src/starter/files.h | 4 - src/whack/.gitignore | 1 - src/whack/Android.mk | 30 - src/whack/Makefile.am | 18 - src/whack/whack.c | 1959 ------- src/whack/whack.h | 352 -- 178 files changed, 3 insertions(+), 69797 deletions(-) delete mode 100644 src/libfreeswan/Android.mk delete mode 100644 src/libfreeswan/Makefile.am delete mode 100644 src/libfreeswan/addrtoa.c delete mode 100644 src/libfreeswan/addrtot.c delete mode 100644 src/libfreeswan/addrtypeof.c delete mode 100644 src/libfreeswan/anyaddr.3 delete mode 100644 src/libfreeswan/anyaddr.c delete mode 100644 src/libfreeswan/atoaddr.3 delete mode 100644 src/libfreeswan/atoaddr.c delete mode 100644 src/libfreeswan/atoasr.3 delete mode 100644 src/libfreeswan/atoasr.c delete mode 100644 src/libfreeswan/atosubnet.c delete mode 100644 src/libfreeswan/atoul.3 delete mode 100644 src/libfreeswan/atoul.c delete mode 100644 src/libfreeswan/copyright.c delete mode 100644 src/libfreeswan/datatot.c delete mode 100644 src/libfreeswan/freeswan.h delete mode 100644 src/libfreeswan/goodmask.3 delete mode 100644 src/libfreeswan/goodmask.c delete mode 100644 src/libfreeswan/initaddr.3 delete mode 100644 src/libfreeswan/initaddr.c delete mode 100644 src/libfreeswan/initsaid.c delete mode 100644 src/libfreeswan/initsubnet.3 delete mode 100644 src/libfreeswan/initsubnet.c delete mode 100644 src/libfreeswan/internal.h delete mode 100644 src/libfreeswan/ipsec_param.h delete mode 100644 src/libfreeswan/pfkey.h delete mode 100644 src/libfreeswan/pfkey_v2_build.c delete mode 100644 src/libfreeswan/pfkey_v2_debug.c delete mode 100644 src/libfreeswan/pfkey_v2_ext_bits.c delete mode 100644 src/libfreeswan/pfkey_v2_parse.c delete mode 100644 src/libfreeswan/pfkeyv2.h delete mode 100644 src/libfreeswan/portof.3 delete mode 100644 src/libfreeswan/portof.c delete mode 100644 src/libfreeswan/rangetoa.c delete mode 100644 src/libfreeswan/rangetosubnet.3 delete mode 100644 src/libfreeswan/rangetosubnet.c delete mode 100644 src/libfreeswan/sameaddr.3 delete mode 100644 src/libfreeswan/sameaddr.c delete mode 100644 src/libfreeswan/satot.c delete mode 100644 src/libfreeswan/subnetof.3 delete mode 100644 src/libfreeswan/subnetof.c delete mode 100644 src/libfreeswan/subnettoa.c delete mode 100644 src/libfreeswan/subnettot.c delete mode 100644 src/libfreeswan/subnettypeof.c delete mode 100644 src/libfreeswan/ttoaddr.3 delete mode 100644 src/libfreeswan/ttoaddr.c delete mode 100644 src/libfreeswan/ttodata.3 delete mode 100644 src/libfreeswan/ttodata.c delete mode 100644 src/libfreeswan/ttoprotoport.c delete mode 100644 src/libfreeswan/ttosa.3 delete mode 100644 src/libfreeswan/ttosa.c delete mode 100644 src/libfreeswan/ttosubnet.c delete mode 100644 src/libfreeswan/ttoul.3 delete mode 100644 src/libfreeswan/ttoul.c delete mode 100644 src/libfreeswan/ultoa.c delete mode 100644 src/libfreeswan/ultot.c delete mode 100644 src/pluto/.gitignore delete mode 100644 src/pluto/Android.mk delete mode 100644 src/pluto/Makefile.am delete mode 100644 src/pluto/ac.c delete mode 100644 src/pluto/ac.h delete mode 100644 src/pluto/adns.c delete mode 100644 src/pluto/adns.h delete mode 100644 src/pluto/alg_info.c delete mode 100644 src/pluto/alg_info.h delete mode 100644 src/pluto/builder.c delete mode 100644 src/pluto/builder.h delete mode 100644 src/pluto/ca.c delete mode 100644 src/pluto/ca.h delete mode 100644 src/pluto/certs.c delete mode 100644 src/pluto/certs.h delete mode 100644 src/pluto/connections.c delete mode 100644 src/pluto/connections.h delete mode 100644 src/pluto/constants.c delete mode 100644 src/pluto/constants.h delete mode 100644 src/pluto/cookie.c delete mode 100644 src/pluto/cookie.h delete mode 100644 src/pluto/crl.c delete mode 100644 src/pluto/crl.h delete mode 100644 src/pluto/crypto.c delete mode 100644 src/pluto/crypto.h delete mode 100644 src/pluto/db_ops.c delete mode 100644 src/pluto/db_ops.h delete mode 100644 src/pluto/defs.c delete mode 100644 src/pluto/defs.h delete mode 100644 src/pluto/demux.c delete mode 100644 src/pluto/demux.h delete mode 100644 src/pluto/dnskey.c delete mode 100644 src/pluto/dnskey.h delete mode 100644 src/pluto/event_queue.c delete mode 100644 src/pluto/event_queue.h delete mode 100644 src/pluto/fetch.c delete mode 100644 src/pluto/fetch.h delete mode 100644 src/pluto/foodgroups.c delete mode 100644 src/pluto/foodgroups.h delete mode 100644 src/pluto/ike_alg.c delete mode 100644 src/pluto/ike_alg.h delete mode 100644 src/pluto/ipsec_doi.c delete mode 100644 src/pluto/ipsec_doi.h delete mode 100644 src/pluto/kameipsec.h delete mode 100644 src/pluto/kernel.c delete mode 100644 src/pluto/kernel.h delete mode 100644 src/pluto/kernel_alg.c delete mode 100644 src/pluto/kernel_alg.h delete mode 100644 src/pluto/kernel_pfkey.c delete mode 100644 src/pluto/kernel_pfkey.h delete mode 100644 src/pluto/keys.c delete mode 100644 src/pluto/keys.h delete mode 100644 src/pluto/lex.c delete mode 100644 src/pluto/lex.h delete mode 100644 src/pluto/log.c delete mode 100644 src/pluto/log.h delete mode 100644 src/pluto/modecfg.c delete mode 100644 src/pluto/modecfg.h delete mode 100644 src/pluto/myid.c delete mode 100644 src/pluto/myid.h delete mode 100644 src/pluto/nat_traversal.c delete mode 100644 src/pluto/nat_traversal.h delete mode 100644 src/pluto/ocsp.c delete mode 100644 src/pluto/ocsp.h delete mode 100644 src/pluto/packet.c delete mode 100644 src/pluto/packet.h delete mode 100644 src/pluto/pkcs7.c delete mode 100644 src/pluto/pkcs7.h delete mode 100644 src/pluto/plugin_list.c delete mode 100644 src/pluto/plugin_list.h delete mode 100644 src/pluto/plugins/xauth/Makefile.am delete mode 100644 src/pluto/plugins/xauth/xauth_default_provider.c delete mode 100644 src/pluto/plugins/xauth/xauth_default_provider.h delete mode 100644 src/pluto/plugins/xauth/xauth_default_verifier.c delete mode 100644 src/pluto/plugins/xauth/xauth_default_verifier.h delete mode 100644 src/pluto/plugins/xauth/xauth_plugin.c delete mode 100644 src/pluto/plugins/xauth/xauth_plugin.h delete mode 100644 src/pluto/pluto.8 delete mode 100644 src/pluto/pluto.c delete mode 100644 src/pluto/pluto.h delete mode 100644 src/pluto/plutomain.c delete mode 100644 src/pluto/rcv_whack.c delete mode 100644 src/pluto/rcv_whack.h delete mode 100644 src/pluto/routing.txt delete mode 100644 src/pluto/rsaref/pkcs11.h delete mode 100644 src/pluto/rsaref/pkcs11f.h delete mode 100644 src/pluto/rsaref/pkcs11t.h delete mode 100644 src/pluto/rsaref/unix.h delete mode 100644 src/pluto/server.c delete mode 100644 src/pluto/server.h delete mode 100644 src/pluto/smartcard.c delete mode 100644 src/pluto/smartcard.h delete mode 100644 src/pluto/spdb.c delete mode 100644 src/pluto/spdb.h delete mode 100644 src/pluto/state.c delete mode 100644 src/pluto/state.h delete mode 100644 src/pluto/timer.c delete mode 100644 src/pluto/timer.h delete mode 100644 src/pluto/vendor.c delete mode 100644 src/pluto/vendor.h delete mode 100644 src/pluto/virtual.c delete mode 100644 src/pluto/virtual.h delete mode 100644 src/pluto/whack_attribute.c delete mode 100644 src/pluto/whack_attribute.h delete mode 100644 src/pluto/x509.c delete mode 100644 src/pluto/x509.h delete mode 100644 src/pluto/xauth/xauth_manager.c delete mode 100644 src/pluto/xauth/xauth_manager.h delete mode 100644 src/pluto/xauth/xauth_provider.h delete mode 100644 src/pluto/xauth/xauth_verifier.h delete mode 100644 src/whack/.gitignore delete mode 100644 src/whack/Android.mk delete mode 100644 src/whack/Makefile.am delete mode 100644 src/whack/whack.c delete mode 100644 src/whack/whack.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 0c19ea3a6..452036b8b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,17 +41,13 @@ if USE_LIBCHARON endif if USE_FILE_CONFIG - SUBDIRS += libfreeswan starter + SUBDIRS += starter endif if USE_IPSEC_SCRIPT SUBDIRS += ipsec _copyright endif -if USE_PLUTO - SUBDIRS += pluto whack -endif - if USE_CHARON SUBDIRS += charon endif @@ -69,7 +65,7 @@ if USE_UPDOWN endif if USE_TOOLS - SUBDIRS += libfreeswan openac scepclient pki + SUBDIRS += openac scepclient pki endif if USE_CONFTEST diff --git a/src/checksum/Makefile.am b/src/checksum/Makefile.am index 58292a45a..0d0da5acf 100644 --- a/src/checksum/Makefile.am +++ b/src/checksum/Makefile.am @@ -79,11 +79,6 @@ if !MONOLITHIC endif endif -if USE_PLUTO - exes += $(top_builddir)/src/pluto/.libs/pluto - AM_CFLAGS += -DP_PLUGINS=\""${p_plugins}\"" -endif - if USE_TOOLS exes += $(top_builddir)/src/openac/.libs/openac exes += $(top_builddir)/src/pki/.libs/pki diff --git a/src/libfreeswan/Android.mk b/src/libfreeswan/Android.mk deleted file mode 100644 index a834d4846..000000000 --- a/src/libfreeswan/Android.mk +++ /dev/null @@ -1,38 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# copy-n-paste from Makefile.am -LOCAL_SRC_FILES := \ -addrtoa.c addrtot.c addrtypeof.c anyaddr.c atoaddr.c atoasr.c \ -atosubnet.c atoul.c copyright.c datatot.c freeswan.h \ -goodmask.c initaddr.c initsaid.c initsubnet.c internal.h ipsec_param.h \ -pfkey_v2_build.c pfkey_v2_debug.c \ -pfkey_v2_ext_bits.c pfkey_v2_parse.c portof.c rangetoa.c \ -pfkey.h pfkeyv2.h rangetosubnet.c sameaddr.c \ -satot.c subnetof.c subnettoa.c subnettot.c \ -subnettypeof.c ttoaddr.c ttodata.c ttoprotoport.c ttosa.c ttosubnet.c ttoul.c \ -ultoa.c ultot.c - -# build libfreeswan ------------------------------------------------------------ - -LOCAL_C_INCLUDES += \ - $(libvstr_PATH) \ - $(strongswan_PATH)/src/include \ - $(strongswan_PATH)/src/libstrongswan \ - $(strongswan_PATH)/src/libhydra \ - $(strongswan_PATH)/src/pluto - -LOCAL_CFLAGS := $(strongswan_CFLAGS) - -LOCAL_MODULE := libfreeswan - -LOCAL_MODULE_TAGS := optional - -LOCAL_ARM_MODE := arm - -LOCAL_PRELINK_MODULE := false - -LOCAL_SHARED_LIBRARIES += libstrongswan - -include $(BUILD_SHARED_LIBRARY) - diff --git a/src/libfreeswan/Makefile.am b/src/libfreeswan/Makefile.am deleted file mode 100644 index b38343d34..000000000 --- a/src/libfreeswan/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -noinst_LIBRARIES = libfreeswan.a -libfreeswan_a_SOURCES = \ -addrtoa.c addrtot.c addrtypeof.c anyaddr.c atoaddr.c atoasr.c \ -atosubnet.c atoul.c copyright.c datatot.c freeswan.h \ -goodmask.c initaddr.c initsaid.c initsubnet.c internal.h ipsec_param.h \ -pfkey_v2_build.c pfkey_v2_debug.c \ -pfkey_v2_ext_bits.c pfkey_v2_parse.c portof.c rangetoa.c \ -pfkey.h pfkeyv2.h rangetosubnet.c sameaddr.c \ -satot.c subnetof.c subnettoa.c subnettot.c \ -subnettypeof.c ttoaddr.c ttodata.c ttoprotoport.c ttosa.c ttosubnet.c ttoul.c \ -ultoa.c ultot.c - -INCLUDES = \ --I$(top_srcdir)/src/libstrongswan \ --I$(top_srcdir)/src/libhydra \ --I$(top_srcdir)/src/pluto - -dist_man3_MANS = anyaddr.3 atoaddr.3 atoasr.3 atoul.3 goodmask.3 initaddr.3 initsubnet.3 \ - portof.3 rangetosubnet.3 sameaddr.3 subnetof.3 \ - ttoaddr.3 ttodata.3 ttosa.3 ttoul.3 - -EXTRA_DIST = Android.mk diff --git a/src/libfreeswan/addrtoa.c b/src/libfreeswan/addrtoa.c deleted file mode 100644 index e1c71da3c..000000000 --- a/src/libfreeswan/addrtoa.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * addresses to ASCII - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -#define NBYTES 4 /* bytes in an address */ -#define PERBYTE 4 /* three digits plus a dot or NUL */ -#define BUFLEN (NBYTES*PERBYTE) - -#if BUFLEN != ADDRTOA_BUF -#error "ADDRTOA_BUF in freeswan.h inconsistent with addrtoa() code" -#endif - -/* - - addrtoa - convert binary address to ASCII dotted decimal - */ -size_t /* space needed for full conversion */ -addrtoa(addr, format, dst, dstlen) -struct in_addr addr; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - unsigned long a = ntohl(addr.s_addr); - int i; - size_t n; - unsigned long byte; - char buf[BUFLEN]; - char *p; - - switch (format) { - case 0: - break; - default: - return 0; - break; - } - - p = buf; - for (i = NBYTES-1; i >= 0; i--) { - byte = (a >> (i*8)) & 0xff; - p += ultoa(byte, 10, p, PERBYTE); - if (i != 0) - *(p-1) = '.'; - } - n = p - buf; - - if (dstlen > 0) { - if (n > dstlen) - buf[dstlen - 1] = '\0'; - strcpy(dst, buf); - } - return n; -} diff --git a/src/libfreeswan/addrtot.c b/src/libfreeswan/addrtot.c deleted file mode 100644 index d1a338730..000000000 --- a/src/libfreeswan/addrtot.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * addresses to text - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -#define IP4BYTES 4 /* bytes in an IPv4 address */ -#define PERBYTE 4 /* three digits plus a dot or NUL */ -#define IP6BYTES 16 /* bytes in an IPv6 address */ - -/* forwards */ -static size_t normal4(const unsigned char *s, size_t len, char *b, char **dp); -static size_t normal6(const unsigned char *s, size_t len, char *b, char **dp, int squish); -static size_t reverse4(const unsigned char *s, size_t len, char *b, char **dp); -static size_t reverse6(const unsigned char *s, size_t len, char *b, char **dp); - -/* - - addrtot - convert binary address to text (dotted decimal or IPv6 string) - */ -size_t /* space needed for full conversion */ -addrtot(src, format, dst, dstlen) -const ip_address *src; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - const unsigned char *b; - size_t n; - char buf[1+ADDRTOT_BUF+1]; /* :address: */ - char *p; - int t = addrtypeof(src); -# define TF(t, f) (((t)<<8) | (f)) - - n = addrbytesptr(src, &b); - if (n == 0) - return 0; - - switch (TF(t, format)) { - case TF(AF_INET, 0): - n = normal4(b, n, buf, &p); - break; - case TF(AF_INET6, 0): - n = normal6(b, n, buf, &p, 1); - break; - case TF(AF_INET, 'Q'): - n = normal4(b, n, buf, &p); - break; - case TF(AF_INET6, 'Q'): - n = normal6(b, n, buf, &p, 0); - break; - case TF(AF_INET, 'r'): - n = reverse4(b, n, buf, &p); - break; - case TF(AF_INET6, 'r'): - n = reverse6(b, n, buf, &p); - break; - default: /* including (AF_INET, 'R') */ - return 0; - break; - } - - if (dstlen > 0) { - if (dstlen < n) - p[dstlen - 1] = '\0'; - strcpy(dst, p); - } - return n; -} - -/* - - normal4 - normal IPv4 address-text conversion - */ -static size_t /* size of text, including NUL */ -normal4(srcp, srclen, buf, dstp) -const unsigned char *srcp; -size_t srclen; -char *buf; /* guaranteed large enough */ -char **dstp; /* where to put result pointer */ -{ - int i; - char *p; - - if (srclen != IP4BYTES) /* "can't happen" */ - return 0; - p = buf; - for (i = 0; i < IP4BYTES; i++) { - p += ultot(srcp[i], 10, p, PERBYTE); - if (i != IP4BYTES - 1) - *(p-1) = '.'; /* overwrites the NUL */ - } - *dstp = buf; - return p - buf; -} - -/* - - normal6 - normal IPv6 address-text conversion - */ -static size_t /* size of text, including NUL */ -normal6(srcp, srclen, buf, dstp, squish) -const unsigned char *srcp; -size_t srclen; -char *buf; /* guaranteed large enough, plus 2 */ -char **dstp; /* where to put result pointer */ -int squish; /* whether to squish out 0:0 */ -{ - int i; - unsigned long piece; - char *p; - char *q; - - if (srclen != IP6BYTES) /* "can't happen" */ - return 0; - p = buf; - *p++ = ':'; - for (i = 0; i < IP6BYTES/2; i++) { - piece = (srcp[2*i] << 8) + srcp[2*i + 1]; - p += ultot(piece, 16, p, 5); /* 5 = abcd + NUL */ - *(p-1) = ':'; /* overwrites the NUL */ - } - *p = '\0'; - q = strstr(buf, ":0:0:"); - if (squish && q != NULL) { /* zero squishing is possible */ - p = q + 1; - while (*p == '0' && *(p+1) == ':') - p += 2; - q++; - *q++ = ':'; /* overwrite first 0 */ - while (*p != '\0') - *q++ = *p++; - *q = '\0'; - if (!(*(q-1) == ':' && *(q-2) == ':')) - *--q = '\0'; /* strip final : unless :: */ - p = buf; - if (!(*p == ':' && *(p+1) == ':')) - p++; /* skip initial : unless :: */ - } else { - q = p; - *--q = '\0'; /* strip final : */ - p = buf + 1; /* skip initial : */ - } - *dstp = p; - return q - p + 1; -} - -/* - - reverse4 - IPv4 reverse-lookup conversion - */ -static size_t /* size of text, including NUL */ -reverse4(srcp, srclen, buf, dstp) -const unsigned char *srcp; -size_t srclen; -char *buf; /* guaranteed large enough */ -char **dstp; /* where to put result pointer */ -{ - int i; - char *p; - - if (srclen != IP4BYTES) /* "can't happen" */ - return 0; - p = buf; - for (i = IP4BYTES-1; i >= 0; i--) { - p += ultot(srcp[i], 10, p, PERBYTE); - *(p-1) = '.'; /* overwrites the NUL */ - } - strcpy(p, "IN-ADDR.ARPA."); - *dstp = buf; - return strlen(buf) + 1; -} - -/* - - reverse6 - IPv6 reverse-lookup conversion (RFC 1886) - * A trifle inefficient, really shouldn't use ultot... - */ -static size_t /* size of text, including NUL */ -reverse6(srcp, srclen, buf, dstp) -const unsigned char *srcp; -size_t srclen; -char *buf; /* guaranteed large enough */ -char **dstp; /* where to put result pointer */ -{ - int i; - unsigned long piece; - char *p; - - if (srclen != IP6BYTES) /* "can't happen" */ - return 0; - p = buf; - for (i = IP6BYTES-1; i >= 0; i--) { - piece = srcp[i]; - p += ultot(piece&0xf, 16, p, 2); - *(p-1) = '.'; - p += ultot(piece>>4, 16, p, 2); - *(p-1) = '.'; - } - strcpy(p, "IP6.ARPA."); - *dstp = buf; - return strlen(buf) + 1; -} - -/* - - reverse6 - modern IPv6 reverse-lookup conversion (RFC 2874) - * this version removed as it was obsoleted in the end. - */ - -#ifdef ADDRTOT_MAIN - -#include -#include -#include -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - if (argc < 2) { - fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n", - argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - exit(0); -} - -struct rtab { - char *input; - char format; - char *output; /* NULL means error expected */ -} rtab[] = { - {"1.2.3.0", 0, "1.2.3.0"}, - {"1:2::3:4", 0, "1:2::3:4"}, - {"1:2::3:4", 'Q', "1:2:0:0:0:0:3:4"}, - {"1:2:0:0:3:4:0:0", 0, "1:2::3:4:0:0"}, - {"1.2.3.4", 'r' , "4.3.2.1.IN-ADDR.ARPA."}, - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - {"1:2::3:4", 'r', "4.0.0.0.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.1.0.0.0.IP6.ARPA."}, - {NULL, 0, NULL} -}; - -void -regress() -{ - struct rtab *r; - int status = 0; - ip_address a; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - - for (r = rtab; r->input != NULL; r++) { - strcpy(in, r->input); - - /* convert it *to* internal format */ - oops = ttoaddr(in, strlen(in), 0, &a); - - /* now convert it back */ - - n = addrtot(&a, r->format, buf, sizeof(buf)); - - if (n == 0 && r->output == NULL) - {} /* okay, error expected */ - - else if (n == 0) { - printf("`%s' atoasr failed\n", r->input); - status = 1; - - } else if (r->output == NULL) { - printf("`%s' atoasr succeeded unexpectedly '%c'\n", - r->input, r->format); - status = 1; - } else { - if (strcasecmp(r->output, buf) != 0) { - printf("`%s' '%c' gave `%s', expected `%s'\n", - r->input, r->format, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* ADDRTOT_MAIN */ diff --git a/src/libfreeswan/addrtypeof.c b/src/libfreeswan/addrtypeof.c deleted file mode 100644 index ee3cc998f..000000000 --- a/src/libfreeswan/addrtypeof.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * extract parts of an ip_address - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - - addrtypeof - get the type of an ip_address - */ -int -addrtypeof(src) -const ip_address *src; -{ - return src->u.v4.sin_family; -} - -/* - - addrbytesptr - get pointer to the address bytes of an ip_address - */ -size_t /* 0 for error */ -addrbytesptr(src, dstp) -const ip_address *src; -const unsigned char **dstp; /* NULL means just a size query */ -{ - const unsigned char *p; - size_t n; - - switch (src->u.v4.sin_family) { - case AF_INET: - p = (const unsigned char *)&src->u.v4.sin_addr.s_addr; - n = 4; - break; - case AF_INET6: - p = (const unsigned char *)&src->u.v6.sin6_addr; - n = 16; - break; - default: - return 0; - break; - } - - if (dstp != NULL) - *dstp = p; - return n; -} - -/* - - addrlenof - get length of the address bytes of an ip_address - */ -size_t /* 0 for error */ -addrlenof(src) -const ip_address *src; -{ - return addrbytesptr(src, NULL); -} - -/* - - addrbytesof - get the address bytes of an ip_address - */ -size_t /* 0 for error */ -addrbytesof(src, dst, dstlen) -const ip_address *src; -unsigned char *dst; -size_t dstlen; -{ - const unsigned char *p; - size_t n; - size_t ncopy; - - n = addrbytesptr(src, &p); - if (n == 0) - return 0; - - if (dstlen > 0) { - ncopy = n; - if (ncopy > dstlen) - ncopy = dstlen; - memcpy(dst, p, ncopy); - } - return n; -} diff --git a/src/libfreeswan/anyaddr.3 b/src/libfreeswan/anyaddr.3 deleted file mode 100644 index 58789cf6c..000000000 --- a/src/libfreeswan/anyaddr.3 +++ /dev/null @@ -1,86 +0,0 @@ -.TH IPSEC_ANYADDR 3 "8 Sept 2000" -.SH NAME -ipsec anyaddr \- get "any" address -.br -ipsec isanyaddr \- test address for equality to "any" address -.br -ipsec unspecaddr \- get "unspecified" address -.br -ipsec isunspecaddr \- test address for equality to "unspecified" address -.br -ipsec loopbackaddr \- get loopback address -.br -ipsec isloopbackaddr \- test address for equality to loopback address -.SH SYNOPSIS -.B "#include -.sp -.B "const char *anyaddr(int af, ip_address *dst);" -.br -.B "int isanyaddr(const ip_address *src);" -.br -.B "const char *unspecaddr(int af, ip_address *dst);" -.br -.B "int isunspecaddr(const ip_address *src);" -.br -.B "const char *loopbackaddr(int af, ip_address *dst);" -.br -.B "int isloopbackaddr(const ip_address *src);" -.SH DESCRIPTION -These functions fill in, and test for, special values of the -.I ip_address -type. -.PP -.I Anyaddr -fills in the destination -.I *dst -with the ``any'' address of address family -.IR af -(normally -.B AF_INET -or -.BR AF_INET6 ). -The IPv4 ``any'' address is the one embodied in the old -.B INADDR_ANY -macro. -.PP -.I Isanyaddr -returns -.B 1 -if the -.I src -address equals the ``any'' address, -and -.B 0 -otherwise. -.PP -Similarly, -.I unspecaddr -supplies, and -.I isunspecaddr -tests for, -the ``unspecified'' address, -which may be the same as the ``any'' address. -.PP -Similarly, -.I loopbackaddr -supplies, and -.I islookbackaddr -tests for, -the loopback address. -.PP -.IR Anyaddr , -.IR unspecaddr , -and -.I loopbackaddr -return -.B NULL -for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.SH SEE ALSO -inet(3), ipsec_addrtot(3), ipsec_sameaddr(3) -.SH DIAGNOSTICS -Fatal errors in the address-supplying functions are: -unknown address family. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. diff --git a/src/libfreeswan/anyaddr.c b/src/libfreeswan/anyaddr.c deleted file mode 100644 index 5b7691b7b..000000000 --- a/src/libfreeswan/anyaddr.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * special addresses - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* OpenSolaris defines strange versions of these macros */ -#ifdef __sun -#undef IN6ADDR_ANY_INIT -#define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}} - -#undef IN6ADDR_LOOPBACK_INIT -#define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}} -#endif - -static struct in6_addr v6any = IN6ADDR_ANY_INIT; -static struct in6_addr v6loop = IN6ADDR_LOOPBACK_INIT; - -/* - - anyaddr - initialize to the any-address value - */ -err_t /* NULL for success, else string literal */ -anyaddr(af, dst) -int af; /* address family */ -ip_address *dst; -{ - uint32_t v4any = htonl(INADDR_ANY); - - switch (af) { - case AF_INET: - return initaddr((unsigned char *)&v4any, sizeof(v4any), af, dst); - break; - case AF_INET6: - return initaddr((unsigned char *)&v6any, sizeof(v6any), af, dst); - break; - default: - return "unknown address family in anyaddr/unspecaddr"; - break; - } -} - -/* - - unspecaddr - initialize to the unspecified-address value - */ -err_t /* NULL for success, else string literal */ -unspecaddr(af, dst) -int af; /* address family */ -ip_address *dst; -{ - return anyaddr(af, dst); -} - -/* - - loopbackaddr - initialize to the loopback-address value - */ -err_t /* NULL for success, else string literal */ -loopbackaddr(af, dst) -int af; /* address family */ -ip_address *dst; -{ - uint32_t v4loop = htonl(INADDR_LOOPBACK); - - switch (af) { - case AF_INET: - return initaddr((unsigned char *)&v4loop, sizeof(v4loop), af, dst); - break; - case AF_INET6: - return initaddr((unsigned char *)&v6loop, sizeof(v6loop), af, dst); - break; - default: - return "unknown address family in loopbackaddr"; - break; - } -} - -/* - - isanyaddr - test for the any-address value - */ -int -isanyaddr(src) -const ip_address *src; -{ - uint32_t v4any = htonl(INADDR_ANY); - int cmp; - - switch (src->u.v4.sin_family) { - case AF_INET: - cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4any, sizeof(v4any)); - break; - case AF_INET6: - cmp = memcmp(&src->u.v6.sin6_addr, &v6any, sizeof(v6any)); - break; - default: - return 0; - break; - } - - return (cmp == 0) ? 1 : 0; -} - -/* - - isunspecaddr - test for the unspecified-address value - */ -int -isunspecaddr(src) -const ip_address *src; -{ - return isanyaddr(src); -} - -/* - - isloopbackaddr - test for the loopback-address value - */ -int -isloopbackaddr(src) -const ip_address *src; -{ - uint32_t v4loop = htonl(INADDR_LOOPBACK); - int cmp; - - switch (src->u.v4.sin_family) { - case AF_INET: - cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4loop, sizeof(v4loop)); - break; - case AF_INET6: - cmp = memcmp(&src->u.v6.sin6_addr, &v6loop, sizeof(v6loop)); - break; - default: - return 0; - break; - } - - return (cmp == 0) ? 1 : 0; -} diff --git a/src/libfreeswan/atoaddr.3 b/src/libfreeswan/atoaddr.3 deleted file mode 100644 index 10da2691c..000000000 --- a/src/libfreeswan/atoaddr.3 +++ /dev/null @@ -1,291 +0,0 @@ -.TH IPSEC_ATOADDR 3 "11 June 2001" -.SH NAME -ipsec atoaddr, addrtoa \- convert Internet addresses to and from ASCII -.br -ipsec atosubnet, subnettoa \- convert subnet/mask ASCII form to and from addresses -.SH SYNOPSIS -.B "#include -.sp -.B "const char *atoaddr(const char *src, size_t srclen," -.ti +1c -.B "struct in_addr *addr);" -.br -.B "size_t addrtoa(struct in_addr addr, int format," -.ti +1c -.B "char *dst, size_t dstlen);" -.sp -.B "const char *atosubnet(const char *src, size_t srclen," -.ti +1c -.B "struct in_addr *addr, struct in_addr *mask);" -.br -.B "size_t subnettoa(struct in_addr addr, struct in_addr mask," -.ti +1c -.B "int format, char *dst, size_t dstlen);" -.SH DESCRIPTION -These functions are obsolete; see -.IR ipsec_ttoaddr (3) -for their replacements. -.PP -.I Atoaddr -converts an ASCII name or dotted-decimal address into a binary address -(in network byte order). -.I Addrtoa -does the reverse conversion, back to an ASCII dotted-decimal address. -.I Atosubnet -and -.I subnettoa -do likewise for the ``address/mask'' ASCII form used to write a -specification of a subnet. -.PP -An address is specified in ASCII as a -dotted-decimal address (e.g. -.BR 1.2.3.4 ), -an eight-digit network-order hexadecimal number with the usual C prefix (e.g. -.BR 0x01020304 , -which is synonymous with -.BR 1.2.3.4 ), -an eight-digit host-order hexadecimal number with a -.B 0h -prefix (e.g. -.BR 0h01020304 , -which is synonymous with -.B 1.2.3.4 -on a big-endian host and -.B 4.3.2.1 -on a little-endian host), -a DNS name to be looked up via -.IR getaddrinfo (3), -or an old-style network name to be looked up via -.IR getnetbyname (3). -.PP -A dotted-decimal address may be incomplete, in which case -ASCII-to-binary conversion implicitly appends -as many instances of -.B .0 -as necessary to bring it up to four components. -The components of a dotted-decimal address are always taken as -decimal, and leading zeros are ignored. -For example, -.B 10 -is synonymous with -.BR 10.0.0.0 , -and -.B 128.009.000.032 -is synonymous with -.BR 128.9.0.32 -(the latter example is verbatim from RFC 1166). -The result of -.I addrtoa -is always complete and does not contain leading zeros. -.PP -The letters in -a hexadecimal address may be uppercase or lowercase or any mixture thereof. -Use of hexadecimal addresses is -.B strongly -.BR discouraged ; -they are included only to save hassles when dealing with -the handful of perverted programs which already print -network addresses in hexadecimal. -.PP -DNS names may be complete (optionally terminated with a ``.'') -or incomplete, and are looked up as specified by local system configuration -(see -.IR resolver (5)). -The first value returned by -.IR getaddrinfo (3) -is used, -so with current DNS implementations, -the result when the name corresponds to more than one address is -difficult to predict. -Name lookup resorts to -.IR getnetbyname (3) -only if -.IR getaddrinfo (3) -fails. -.PP -A subnet specification is of the form \fInetwork\fB/\fImask\fR. -The -.I network -and -.I mask -can be any form acceptable to -.IR atoaddr . -In addition, the -.I mask -can be a decimal integer (leading zeros ignored) giving a bit count, -in which case -it stands for a mask with that number of high bits on and all others off -(e.g., -.B 24 -means -.BR 255.255.255.0 ). -In any case, the mask must be contiguous -(a sequence of high bits on and all remaining low bits off). -As a special case, the subnet specification -.B %default -is a synonym for -.BR 0.0.0.0/0 . -.PP -.I Atosubnet -ANDs the mask with the address before returning, -so that any non-network bits in the address are turned off -(e.g., -.B 10.1.2.3/24 -is synonymous with -.BR 10.1.2.0/24 ). -.I Subnettoa -generates the decimal-integer-bit-count -form of the mask, -with no leading zeros, -unless the mask is non-contiguous. -.PP -The -.I srclen -parameter of -.I atoaddr -and -.I atosubnet -specifies the length of the ASCII string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I dstlen -parameter of -.I addrtoa -and -.I subnettoa -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.I freeswan.h -header file defines constants, -.B ADDRTOA_BUF -and -.BR SUBNETTOA_BUF , -which are the sizes of buffers just large enough for worst-case results. -.PP -The -.I format -parameter of -.I addrtoa -and -.I subnettoa -specifies what format is to be used for the conversion. -The value -.B 0 -(not the ASCII character -.BR '0' , -but a zero value) -specifies a reasonable default, -and is in fact the only format currently available. -This parameter is a hedge against future needs. -.PP -The ASCII-to-binary functions return NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -The binary-to-ASCII functions return -.B 0 -for a failure, and otherwise -always return the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.SH SEE ALSO -inet(3) -.SH DIAGNOSTICS -Fatal errors in -.I atoaddr -are: -empty input; -attempt to allocate temporary storage for a very long name failed; -name lookup failed; -syntax error in dotted-decimal form; -dotted-decimal component too large to fit in 8 bits. -.PP -Fatal errors in -.I atosubnet -are: -no -.B / -in -.IR src ; -.I atoaddr -error in conversion of -.I network -or -.IR mask ; -bit-count mask too big; -mask non-contiguous. -.PP -Fatal errors in -.I addrtoa -and -.I subnettoa -are: -unknown format. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The interpretation of incomplete dotted-decimal addresses -(e.g. -.B 10/24 -means -.BR 10.0.0.0/24 ) -differs from that of some older conversion -functions, e.g. those of -.IR inet (3). -The behavior of the older functions has never been -particularly consistent or particularly useful. -.PP -Ignoring leading zeros in dotted-decimal components and bit counts -is arguably the most useful behavior in this application, -but it might occasionally cause confusion with the historical use of leading -zeros to denote octal numbers. -.PP -It is barely possible that somebody, somewhere, -might have a legitimate use for non-contiguous subnet masks. -.PP -.IR Getnetbyname (3) -is a historical dreg. -.PP -The restriction of ASCII-to-binary error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The ASCII-to-binary error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = atoaddr( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/atoaddr.c b/src/libfreeswan/atoaddr.c deleted file mode 100644 index a3643801e..000000000 --- a/src/libfreeswan/atoaddr.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * conversion from ASCII forms of addresses to internal ones - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - * Define NOLEADINGZEROS to interpret 032 as an error, not as 32. There - * is deliberately no way to interpret it as 26 (i.e., as octal). - */ - -/* - * Legal characters in a domain name. Underscore technically is not, - * but is a common misunderstanding. - */ -static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_."; - -static const char *try8hex(const char *, size_t, struct in_addr *); -static const char *try8hosthex(const char *, size_t, struct in_addr *); -static const char *trydotted(const char *, size_t, struct in_addr *); -static const char *getbyte(const char **, const char *, int *); - -/* - - atoaddr - convert ASCII name or dotted-decimal address to binary address - */ -const char * /* NULL for success, else string literal */ -atoaddr(src, srclen, addrp) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -struct in_addr *addrp; -{ - struct addrinfo hints, *res; - struct netent *ne = NULL; - const char *oops, *msg = NULL; -# define HEXLEN 10 /* strlen("0x11223344") */ -# ifndef ATOADDRBUF -# define ATOADDRBUF 100 -# endif - char namebuf[ATOADDRBUF]; - char *p = namebuf; - char *q; - int error; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - /* might it be hex? */ - if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'x')) - return try8hex(src+2, srclen-2, addrp); - if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'h')) - return try8hosthex(src+2, srclen-2, addrp); - - /* try it as dotted decimal */ - oops = trydotted(src, srclen, addrp); - if (oops == NULL) - return NULL; /* it worked */ - if (*oops != '?') - return oops; /* it *was* probably meant as a d.q. */ - - /* try it as a name -- first, NUL-terminate it */ - if (srclen > sizeof(namebuf)-1) { - p = (char *) MALLOC(srclen+1); - if (p == NULL) - return "unable to allocate temporary space for name"; - } - p[0] = '\0'; - strncat(p, src, srclen); - - /* next, check that it's a vaguely legal name */ - for (q = p; *q != '\0'; q++) - { - if (!isprint(*q)) - { - msg = "unprintable character in name"; - goto error; - } - } - if (strspn(p, namechars) != srclen) - { - msg = "illegal (non-DNS-name) character in name"; - goto error; - } - - /* try as host name, failing that as /etc/networks network name */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - error = getaddrinfo(p, NULL, &hints, &res); - if (error != 0) - { - ne = getnetbyname(p); - if (ne == NULL) - { - msg = "name lookup failed"; - goto error; - } - addrp->s_addr = htonl(ne->n_net); - } - else - { - struct sockaddr_in *in = (struct sockaddr_in*)res->ai_addr; - memcpy(&addrp->s_addr, &in->sin_addr.s_addr, sizeof(addrp->s_addr)); - freeaddrinfo(res); - } - -error: - if (p != namebuf) - { - FREE(p); - } - - return msg; -} - -/* - - try8hosthex - try conversion as an eight-digit host-order hex number - */ -const char * /* NULL for success, else string literal */ -try8hosthex(src, srclen, addrp) -const char *src; -size_t srclen; /* should be 8 */ -struct in_addr *addrp; -{ - const char *oops; - unsigned long addr; - - if (srclen != 8) - return "internal error, try8hex called with bad length"; - - oops = atoul(src, srclen, 16, &addr); - if (oops != NULL) - return oops; - - addrp->s_addr = addr; - return NULL; -} - -/* - - try8hex - try conversion as an eight-digit network-order hex number - */ -const char * /* NULL for success, else string literal */ -try8hex(src, srclen, addrp) -const char *src; -size_t srclen; /* should be 8 */ -struct in_addr *addrp; -{ - const char *oops; - - oops = try8hosthex(src, srclen, addrp); - if (oops != NULL) - return oops; - - addrp->s_addr = htonl(addrp->s_addr); - return NULL; -} - -/* - - trydotted - try conversion as dotted decimal - * - * If the first char of a complaint is '?', that means "didn't look like - * dotted decimal at all". - */ -const char * /* NULL for success, else string literal */ -trydotted(src, srclen, addrp) -const char *src; -size_t srclen; -struct in_addr *addrp; -{ - const char *stop = src + srclen; /* just past end */ - int byte; - const char *oops; - unsigned long addr; - int i; -# define NBYTES 4 -# define BYTE 8 - - addr = 0; - for (i = 0; i < NBYTES && src < stop; i++) { - oops = getbyte(&src, stop, &byte); - if (oops != NULL) { - if (*oops != '?') - return oops; /* bad number */ - if (i > 1) - return oops+1; /* failed number */ - return oops; /* with leading '?' */ - } - addr = (addr << BYTE) | byte; - if (i < 3 && src < stop && *src++ != '.') { - if (i == 0) - return "?syntax error in dotted-decimal address"; - else - return "syntax error in dotted-decimal address"; - } - } - addr <<= (NBYTES - i) * BYTE; - if (src != stop) - return "extra garbage on end of dotted-decimal address"; - - addrp->s_addr = htonl(addr); - return NULL; -} - -/* - - getbyte - try to scan a byte in dotted decimal - * A subtlety here is that all this arithmetic on ASCII digits really is - * highly portable -- ANSI C guarantees that digits 0-9 are contiguous. - * It's easier to just do it ourselves than set up for a call to atoul(). - * - * If the first char of a complaint is '?', that means "didn't look like a - * number at all". - */ -const char * /* NULL for success, else string literal */ -getbyte(srcp, stop, retp) -const char **srcp; /* *srcp is updated */ -const char *stop; /* first untouchable char */ -int *retp; /* return-value pointer */ -{ - char c; - const char *p; - int no; - - if (*srcp >= stop) - return "?empty number in dotted-decimal address"; - - if (stop - *srcp >= 3 && **srcp == '0' && CIEQ(*(*srcp+1), 'x')) - return "hex numbers not supported in dotted-decimal addresses"; -#ifdef NOLEADINGZEROS - if (stop - *srcp >= 2 && **srcp == '0' && isdigit(*(*srcp+1))) - return "octal numbers not supported in dotted-decimal addresses"; -#endif /* NOLEADINGZEROS */ - - /* must be decimal, if it's numeric at all */ - no = 0; - p = *srcp; - while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') { - no = no*10 + (c - '0'); - p++; - } - if (p == *srcp) - return "?non-numeric component in dotted-decimal address"; - *srcp = p; - if (no > 255) - return "byte overflow in dotted-decimal address"; - *retp = no; - return NULL; -} diff --git a/src/libfreeswan/atoasr.3 b/src/libfreeswan/atoasr.3 deleted file mode 100644 index 0b9a5fea3..000000000 --- a/src/libfreeswan/atoasr.3 +++ /dev/null @@ -1,185 +0,0 @@ -.TH IPSEC_ATOASR 3 "11 June 2001" -.SH NAME -ipsec atoasr \- convert ASCII to Internet address, subnet, or range -.br -ipsec rangetoa \- convert Internet address range to ASCII -.SH SYNOPSIS -.B "#include -.sp -.B "const char *atoasr(const char *src, size_t srclen," -.ti +1c -.B "char *type, struct in_addr *addrs);" -.br -.B "size_t rangetoa(struct in_addr *addrs, int format, -.ti +1c -.B "char *dst, size_t dstlen);" -.SH DESCRIPTION -These functions are obsolete; -there is no current equivalent, -because so far they have not proved useful. -.PP -.I Atoasr -converts an ASCII address, subnet, or address range -into a suitable combination of binary addresses -(in network byte order). -.I Rangetoa -converts an address range back into ASCII, -using dotted-decimal form for the addresses -(the other reverse conversions are handled by -.IR ipsec_addrtoa (3) -and -.IR ipsec_subnettoa (3)). -.PP -A single address can be any form acceptable to -.IR ipsec_atoaddr (3): -dotted decimal, DNS name, or hexadecimal number. -A subnet -specification uses the form \fInetwork\fB/\fImask\fR -interpreted by -.IR ipsec_atosubnet (3). -.PP -An address range is two -.IR ipsec_atoaddr (3) -addresses separated by a -.B ... -delimiter. -If there are four dots rather than three, the first is taken as -part of the begin address, -e.g. for a complete DNS name which ends with -.B . -to suppress completion attempts. -The begin address of a range must be -less than or equal to the end address. -.PP -The -.I srclen -parameter of -.I atoasr -specifies the length of the ASCII string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I type -parameter of -.I atoasr -must point to a -.B char -variable used to record which form was found. -The -.I addrs -parameter must point to a two-element array of -.B "struct in_addr" -which receives the results. -The values stored into -.BR *type , -and the corresponding values in the array, are: -.PP -.ta 3c +2c +3c - *type addrs[0] addrs[1] -.sp 0.8 -address \&\fB'a'\fR address - -.br -subnet \&\fB's'\fR network mask -.br -range \&\fB'r'\fR begin end -.PP -The -.I dstlen -parameter of -.I rangetoa -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.I freeswan.h -header file defines a constant, -.BR RANGETOA_BUF , -which is the size of a buffer just large enough for worst-case results. -.PP -The -.I format -parameter of -.I rangetoa -specifies what format is to be used for the conversion. -The value -.B 0 -(not the ASCII character -.BR '0' , -but a zero value) -specifies a reasonable default, -and is in fact the only format currently available. -This parameter is a hedge against future needs. -.PP -.I Atoasr -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.I Rangetoa -returns -.B 0 -for a failure, and otherwise -always returns the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.SH SEE ALSO -ipsec_atoaddr(3), ipsec_atosubnet(3) -.SH DIAGNOSTICS -Fatal errors in -.I atoasr -are: -empty input; -error in -.IR ipsec_atoaddr (3) -or -.IR ipsec_atosubnet (3) -during conversion; -begin address of range exceeds end address. -.PP -Fatal errors in -.I rangetoa -are: -unknown format. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The restriction of error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = atoasr( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/atoasr.c b/src/libfreeswan/atoasr.c deleted file mode 100644 index ad62ef46b..000000000 --- a/src/libfreeswan/atoasr.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * convert from ASCII form of address/subnet/range to binary - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - atoasr - convert ASCII to address, subnet, or range - */ -const char * /* NULL for success, else string literal */ -atoasr(src, srclen, typep, addrsp) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -char *typep; /* return type code: 'a', 's', 'r' */ -struct in_addr addrsp[2]; -{ - const char *punct; - const char *stop; - const char *oops; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - /* subnet is easy to spot */ - punct = memchr(src, '/', srclen); - if (punct != NULL) { - *typep = 's'; - return atosubnet(src, srclen, &addrsp[0], &addrsp[1]); - } - - /* try for a range */ - stop = src + srclen; - for (punct = src; (punct = memchr(punct, '.', stop - punct)) != NULL; - punct++) - if (stop - punct > 3 && *(punct+1) == '.' && *(punct+2) == '.') - break; /* NOTE BREAK OUT */ - if (punct == NULL) { - /* didn't find the range delimiter, must be plain address */ - *typep = 'a'; - return atoaddr(src, srclen, &addrsp[0]); - } - - /* looks like a range */ - *typep = 'r'; - if (stop - punct > 4 && *(punct+3) == '.') - punct++; /* first dot is trailing dot of name */ - oops = atoaddr(src, punct - src, &addrsp[0]); - if (oops != NULL) - return oops; - oops = atoaddr(punct+3, stop - (punct+3), &addrsp[1]); - if (oops != NULL) - return oops; - if (ntohl(addrsp[0].s_addr) > ntohl(addrsp[1].s_addr)) - return "invalid range, begin > end"; - return NULL; -} - - - -#ifdef ATOASR_MAIN - -#include -#include -#include -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - struct in_addr a[2]; - char buf[100]; - const char *oops; - size_t n; - char type; - - if (argc < 2) { - fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n", - argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - oops = atoasr(argv[1], 0, &type, a); - if (oops != NULL) { - fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); - exit(1); - } - switch (type) { - case 'a': - n = addrtoa(a[0], 0, buf, sizeof(buf)); - break; - case 's': - n = subnettoa(a[0], a[1], 0, buf, sizeof(buf)); - break; - case 'r': - n = rangetoa(a, 0, buf, sizeof(buf)); - break; - default: - fprintf(stderr, "%s: unknown type '%c'\n", argv[0], type); - exit(1); - break; - } - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conversion of ", argv[0]); - fprintf(stderr, "%s ", inet_ntoa(a[0])); - fprintf(stderr, "%s", inet_ntoa(a[1])); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - char *input; - char *output; /* NULL means error expected */ -} rtab[] = { - {"1.2.3.0", "1.2.3.0"}, - {"1.2.3.0/255.255.255.0", "1.2.3.0/24"}, - {"1.2.3.0...1.2.3.5", "1.2.3.0...1.2.3.5"}, - {"1.2.3.4.5", NULL}, - {"1.2.3.4/", NULL}, - {"1.2.3.4...", NULL}, - {"1.2.3.4....", NULL}, - {"localhost/32", "127.0.0.1/32"}, - {"localhost...127.0.0.3", "127.0.0.1...127.0.0.3"}, - {"127.0.0.0...localhost", "127.0.0.0...127.0.0.1"}, - {"127.0.0.3...localhost", NULL}, - {NULL, NULL} -}; - -void -regress(void) -{ - struct rtab *r; - int status = 0; - struct in_addr a[2]; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - char type; - - for (r = rtab; r->input != NULL; r++) { - strcpy(in, r->input); - oops = atoasr(in, 0, &type, a); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s' atoasr failed: %s\n", r->input, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s' atoasr succeeded unexpectedly '%c'\n", - r->input, type); - status = 1; - } else { - switch (type) { - case 'a': - n = addrtoa(a[0], 0, buf, sizeof(buf)); - break; - case 's': - n = subnettoa(a[0], a[1], 0, buf, sizeof(buf)); - break; - case 'r': - n = rangetoa(a, 0, buf, sizeof(buf)); - break; - default: - fprintf(stderr, "`%s' unknown type '%c'\n", - r->input, type); - n = 0; - status = 1; - break; - } - if (n > sizeof(buf)) { - printf("`%s' '%c' reverse failed: need %ld\n", - r->input, type, (long)n); - status = 1; - } else if (n > 0 && strcmp(r->output, buf) != 0) { - printf("`%s' '%c' gave `%s', expected `%s'\n", - r->input, type, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* ATOASR_MAIN */ diff --git a/src/libfreeswan/atosubnet.c b/src/libfreeswan/atosubnet.c deleted file mode 100644 index 8b2bfa17e..000000000 --- a/src/libfreeswan/atosubnet.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * convert from ASCII form of subnet specification to binary - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -#ifndef DEFAULTSUBNET -#define DEFAULTSUBNET "%default" -#endif - -/* - - atosubnet - convert ASCII "addr/mask" to address and mask - * Mask can be integer bit count. - */ -const char * /* NULL for success, else string literal */ -atosubnet(src, srclen, addrp, maskp) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -struct in_addr *addrp; -struct in_addr *maskp; -{ - const char *slash; - const char *mask; - size_t mlen; - const char *oops; - unsigned long bc; - static char def[] = DEFAULTSUBNET; -# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */ - static char defis[] = "0/0"; -# define DEFILEN (sizeof(defis) - 1) - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) { - src = defis; - srclen = DEFILEN; - } - - slash = memchr(src, '/', srclen); - if (slash == NULL) - return "no / in subnet specification"; - mask = slash + 1; - mlen = srclen - (mask - src); - - oops = atoaddr(src, slash-src, addrp); - if (oops != NULL) - return oops; - - oops = atoul(mask, mlen, 10, &bc); - if (oops == NULL) { - /* atoul succeeded, it's a bit-count mask */ - if (bc > ABITS) - return "bit-count mask too large"; -#ifdef NOLEADINGZEROS - if (mlen > 1 && *mask == '0') - return "octal not allowed in mask"; -#endif /* NOLEADINGZEROS */ - *maskp = bitstomask((int)bc); - } else { - oops = atoaddr(mask, mlen, maskp); - if (oops != NULL) - return oops; - if (!goodmask(*maskp)) - return "non-contiguous mask"; - } - - addrp->s_addr &= maskp->s_addr; - return NULL; -} - - - -#ifdef ATOSUBNET_MAIN - -#include -#include -#include -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - struct in_addr a; - struct in_addr m; - char buf[100]; - const char *oops; - size_t n; - - if (argc < 2) { - fprintf(stderr, "Usage: %s {addr/mask|-r}\n", argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - oops = atosubnet(argv[1], 0, &a, &m); - if (oops != NULL) { - fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); - exit(1); - } - n = subnettoa(a, m, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conversion of ", argv[0]); - fprintf(stderr, "%s/", inet_ntoa(a)); - fprintf(stderr, "%s", inet_ntoa(m)); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - char *input; - char *output; /* NULL means error expected */ -} rtab[] = { - {"1.2.3.0/255.255.255.0", "1.2.3.0/24"}, - {"1.2.3.0/24", "1.2.3.0/24"}, - {"1.2.3.1/255.255.255.240", "1.2.3.0/28"}, - {"1.2.3.1/32", "1.2.3.1/32"}, - {"1.2.3.1/0", "0.0.0.0/0"}, -/* "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0", */ - {"1.2.3.1/255.255.127.0", NULL}, - {"128.009.000.032/32", "128.9.0.32/32"}, - {"128.0x9.0.32/32", NULL}, - {"0x80090020/32", "128.9.0.32/32"}, - {"0x800x0020/32", NULL}, - {"128.9.0.32/0xffFF0000", "128.9.0.0/16"}, - {"128.9.0.32/0xff0000FF", NULL}, - {"128.9.0.32/0x0000ffFF", NULL}, - {"128.9.0.32/0x00ffFF0000", NULL}, - {"128.9.0.32/0xffFF", NULL}, - {"128.9.0.32.27/32", NULL}, - {"128.9.0k32/32", NULL}, - {"328.9.0.32/32", NULL}, - {"128.9..32/32", NULL}, - {"10/8", "10.0.0.0/8"}, - {"10.0/8", "10.0.0.0/8"}, - {"10.0.0/8", "10.0.0.0/8"}, - {"10.0.1/24", "10.0.1.0/24"}, - {"_", NULL}, - {"_/_", NULL}, - {"1.2.3.1", NULL}, - {"1.2.3.1/_", NULL}, - {"1.2.3.1/24._", NULL}, - {"1.2.3.1/99", NULL}, - {"localhost/32", "127.0.0.1/32"}, - {"%default", "0.0.0.0/0"}, - {NULL, NULL} -}; - -void -regress() -{ - struct rtab *r; - int status = 0; - struct in_addr a; - struct in_addr m; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - - for (r = rtab; r->input != NULL; r++) { - strcpy(in, r->input); - oops = atosubnet(in, 0, &a, &m); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s' atosubnet failed: %s\n", r->input, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s' atosubnet succeeded unexpectedly\n", - r->input); - status = 1; - } else { - n = subnettoa(a, m, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - printf("`%s' subnettoa failed: need %ld\n", - r->input, (long)n); - status = 1; - } else if (strcmp(r->output, buf) != 0) { - printf("`%s' gave `%s', expected `%s'\n", - r->input, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* ATOSUBNET_MAIN */ diff --git a/src/libfreeswan/atoul.3 b/src/libfreeswan/atoul.3 deleted file mode 100644 index 6737b6b54..000000000 --- a/src/libfreeswan/atoul.3 +++ /dev/null @@ -1,160 +0,0 @@ -.TH IPSEC_ATOUL 3 "11 June 2001" -.SH NAME -ipsec atoul, ultoa \- convert unsigned-long numbers to and from ASCII -.SH SYNOPSIS -.B "#include -.sp -.B "const char *atoul(const char *src, size_t srclen," -.ti +1c -.B "int base, unsigned long *n);" -.br -.B "size_t ultoa(unsigned long n, int base, char *dst," -.ti +1c -.B "size_t dstlen);" -.SH DESCRIPTION -These functions are obsolete; see -.IR ipsec_ttoul (3) -for their replacements. -.PP -.I Atoul -converts an ASCII number into a binary -.B "unsigned long" -value. -.I Ultoa -does the reverse conversion, back to an ASCII version. -.PP -Numbers are specified in ASCII as -decimal (e.g. -.BR 123 ), -octal with a leading zero (e.g. -.BR 012 , -which has value 10), -or hexadecimal with a leading -.B 0x -(e.g. -.BR 0x1f , -which has value 31) -in either upper or lower case. -.PP -The -.I srclen -parameter of -.I atoul -specifies the length of the ASCII string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I base -parameter of -.I atoul -can be -.BR 8 , -.BR 10 , -or -.BR 16 , -in which case the number supplied is assumed to be of that form -(and in the case of -.BR 16 , -to lack any -.B 0x -prefix). -It can also be -.BR 0 , -in which case the number is examined for a leading zero -or a leading -.B 0x -to determine its base, -or -.B 13 -(halfway between 10 and 16), -which has the same effect as -.B 0 -except that a non-hexadecimal -number is considered decimal regardless of any leading zero. -.PP -The -.I dstlen -parameter of -.I ultoa -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -.PP -The -.I base -parameter of -.I ultoa -must be -.BR 8 , -.BR 10 , -or -.BR 16 . -.PP -.I Atoul -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.I Ultoa -returns the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.SH SEE ALSO -atol(3), strtoul(3) -.SH DIAGNOSTICS -Fatal errors in -.I atoul -are: -empty input; -unknown -.IR base ; -non-digit character found; -number too large for an -.BR "unsigned long" . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -There is no provision for reporting an invalid -.I base -parameter given to -.IR ultoa . -.PP -The restriction of error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The error-reporting convention lends itself to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = atoul( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/atoul.c b/src/libfreeswan/atoul.c deleted file mode 100644 index d8e1528cb..000000000 --- a/src/libfreeswan/atoul.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * convert from ASCII form of unsigned long to binary - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - atoul - convert ASCII substring to unsigned long number - */ -const char * /* NULL for success, else string literal */ -atoul(src, srclen, base, resultp) -const char *src; -size_t srclen; /* 0 means strlen(src) */ -int base; /* 0 means figure it out */ -unsigned long *resultp; -{ - const char *stop; - static char hex[] = "0123456789abcdef"; - static char uchex[] = "0123456789ABCDEF"; - int d; - char c; - char *p; - unsigned long r; - unsigned long rlimit; - int dlimit; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - if (base == 0 || base == 13) { - if (srclen > 2 && *src == '0' && CIEQ(*(src+1), 'x')) - return atoul(src+2, srclen-2, 16, resultp); - if (srclen > 1 && *src == '0' && base != 13) - return atoul(src+1, srclen-1, 8, resultp); - return atoul(src, srclen, 10, resultp); - } - if (base != 8 && base != 10 && base != 16) - return "unsupported number base"; - - r = 0; - stop = src + srclen; - if (base == 16) { - while (src < stop) { - c = *src++; - p = strchr(hex, c); - if (p != NULL) - d = p - hex; - else { - p = strchr(uchex, c); - if (p == NULL) - return "non-hex-digit in hex number"; - d = p - uchex; - } - r = (r << 4) | d; - } - /* defer length check to catch invalid digits first */ - if (srclen > sizeof(unsigned long) * 2) - return "hex number too long"; - } else { - rlimit = ULONG_MAX / base; - dlimit = (int)(ULONG_MAX - rlimit*base); - while (src < stop) { - c = *src++; - d = c - '0'; - if (d < 0 || d >= base) - return "non-digit in number"; - if (r > rlimit || (r == rlimit && d > dlimit)) - return "unsigned-long overflow"; - r = r*base + d; - } - } - - *resultp = r; - return NULL; -} diff --git a/src/libfreeswan/copyright.c b/src/libfreeswan/copyright.c deleted file mode 100644 index e55e849f7..000000000 --- a/src/libfreeswan/copyright.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * return IPsec copyright notice - * Copyright (C) 2001, 2002 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -static const char *co[] = { - "Copyright (C) 1999-2009 Henry Spencer, Richard Guy Briggs,", - " D. Hugh Redelmeier, Sandy Harris, Claudia Schmeing,", - " Michael Richardson, Angelos D. Keromytis, John Ioannidis,", - "", - " Ken Bantoft, Stephen J. Bevan, JuanJo Ciarlante, Mathieu Lafon,", - " Stephane Laroche, Kai Martius, Stephan Scholz, Tuomo Soini, Herbert Xu,", - "", - " Martin Berner, Marco Bertossa, David Buechi, Ueli Galizzi,", - " Christoph Gysin, Andreas Hess, Patric Lichtsteiner, Michael Meier,", - " Andreas Schleiss, Ariane Seiler, Mario Strasser, Lukas Suter,", - " Roger Wegmann, Simon Zwahlen,", - " ZHW Zuercher Hochschule Winterthur (Switzerland).", - "", - " Philip Boetschi, Tobias Brunner, Sansar Choinyambuu, Adrian Doerig,", - " Andreas Eigenmann, Fabian Hartmann, Noah Heusser, Jan Hutter,", - " Thomas Kallenberg, Daniel Roethlisberger, Joel Stillhart, Martin Willi,", - " Daniel Wydler, Andreas Steffen,", - " HSR Hochschule fuer Technik Rapperswil (Switzerland).", - "", - "This program is free software; you can redistribute it and/or modify it", - "under the terms of the GNU General Public License as published by the", - "Free Software Foundation; either version 2 of the License, or (at your", - "option) any later version. See .", - "", - "This program is distributed in the hope that it will be useful, but", - "WITHOUT ANY WARRANTY; without even the implied warranty of", - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General", - "Public License (file COPYING in the distribution) for more details.", - NULL -}; - -/* - - ipsec_copyright_notice - return copyright notice, as a vector of strings - */ -const char ** -ipsec_copyright_notice() -{ - return co; -} diff --git a/src/libfreeswan/datatot.c b/src/libfreeswan/datatot.c deleted file mode 100644 index e3b9d6417..000000000 --- a/src/libfreeswan/datatot.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * convert from binary data (e.g. key) to text form - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -static void convert(const char *src, size_t nreal, int format, char *out); - -/* - - datatot - convert data bytes to text - */ -size_t /* true length (with NUL) for success */ -datatot(src, srclen, format, dst, dstlen) -const char *src; -size_t srclen; -int format; /* character indicating what format */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t inblocksize; /* process this many bytes at a time */ - size_t outblocksize; /* producing this many */ - size_t breakevery; /* add a _ every this many (0 means don't) */ - size_t sincebreak; /* output bytes since last _ */ - char breakchar; /* character used to break between groups */ - char inblock[10]; /* enough for any format */ - char outblock[10]; /* enough for any format */ - char fake[1]; /* fake output area for dstlen == 0 */ - size_t needed; /* return value */ - char *stop; /* where the terminating NUL will go */ - size_t ntodo; /* remaining input */ - size_t nreal; - char *out; - char *prefix; - - breakevery = 0; - breakchar = '_'; - - switch (format) { - case 0: - case 'h': - format = 'x'; - breakevery = 8; - /* FALLTHROUGH */ - case 'x': - inblocksize = 1; - outblocksize = 2; - prefix = "0x"; - break; - case ':': - breakevery = 2; - breakchar = ':'; - /* FALLTHROUGH */ - case 16: - inblocksize = 1; - outblocksize = 2; - prefix = ""; - format = 'x'; - break; - case 's': - inblocksize = 3; - outblocksize = 4; - prefix = "0s"; - break; - case 64: /* beware, equals ' ' */ - inblocksize = 3; - outblocksize = 4; - prefix = ""; - format = 's'; - break; - default: - return 0; - break; - } - assert(inblocksize < sizeof(inblock)); - assert(outblocksize < sizeof(outblock)); - assert(breakevery % outblocksize == 0); - - if (srclen == 0) - return 0; - ntodo = srclen; - - if (dstlen == 0) { /* dispose of awkward special case */ - dst = fake; - dstlen = 1; - } - stop = dst + dstlen - 1; - - nreal = strlen(prefix); - needed = nreal; /* for starters */ - if (dstlen <= nreal) { /* prefix won't fit */ - strncpy(dst, prefix, dstlen - 1); - dst += dstlen - 1; - } else { - strcpy(dst, prefix); - dst += nreal; - } - assert(dst <= stop); - sincebreak = 0; - - while (ntodo > 0) { - if (ntodo < inblocksize) { /* incomplete input */ - memset(inblock, 0, sizeof(inblock)); - memcpy(inblock, src, ntodo); - src = inblock; - nreal = ntodo; - ntodo = inblocksize; - } else - nreal = inblocksize; - out = (outblocksize > stop - dst) ? outblock : dst; - - convert(src, nreal, format, out); - needed += outblocksize; - sincebreak += outblocksize; - if (dst < stop) { - if (out != dst) { - assert(outblocksize > stop - dst); - memcpy(dst, out, stop - dst); - dst = stop; - } else - dst += outblocksize; - } - - src += inblocksize; - ntodo -= inblocksize; - if (breakevery != 0 && sincebreak >= breakevery && ntodo > 0) { - if (dst < stop) - *dst++ = breakchar; - needed++; - sincebreak = 0; - } - } - - assert(dst <= stop); - *dst++ = '\0'; - needed++; - - return needed; -} - -/* - - convert - convert one input block to one output block - */ -static void -convert(src, nreal, format, out) -const char *src; -size_t nreal; /* how much of the input block is real */ -int format; -char *out; -{ - static char hex[] = "0123456789abcdef"; - static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - unsigned char c; - unsigned char c1, c2, c3; - - assert(nreal > 0); - switch (format) { - case 'x': - assert(nreal == 1); - c = (unsigned char)*src; - *out++ = hex[c >> 4]; - *out++ = hex[c & 0xf]; - break; - case 's': - c1 = (unsigned char)*src++; - c2 = (unsigned char)*src++; - c3 = (unsigned char)*src++; - *out++ = base64[c1 >> 2]; /* top 6 bits of c1 */ - c = (c1 & 0x3) << 4; /* bottom 2 of c1... */ - c |= c2 >> 4; /* ...top 4 of c2 */ - *out++ = base64[c]; - if (nreal == 1) - *out++ = '='; - else { - c = (c2 & 0xf) << 2; /* bottom 4 of c2... */ - c |= c3 >> 6; /* ...top 2 of c3 */ - *out++ = base64[c]; - } - if (nreal <= 2) - *out++ = '='; - else - *out++ = base64[c3 & 0x3f]; /* bottom 6 of c3 */ - break; - default: - assert(nreal == 0); /* unknown format */ - break; - } -} - -/* - - datatoa - convert data to ASCII - * backward-compatibility synonym for datatot - */ -size_t /* true length (with NUL) for success */ -datatoa(src, srclen, format, dst, dstlen) -const char *src; -size_t srclen; -int format; /* character indicating what format */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - return datatot(src, srclen, format, dst, dstlen); -} - -/* - - bytestoa - convert data bytes to ASCII - * backward-compatibility synonym for datatot - */ -size_t /* true length (with NUL) for success */ -bytestoa(src, srclen, format, dst, dstlen) -const char *src; -size_t srclen; -int format; /* character indicating what format */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - return datatot(src, srclen, format, dst, dstlen); -} diff --git a/src/libfreeswan/freeswan.h b/src/libfreeswan/freeswan.h deleted file mode 100644 index 724165bde..000000000 --- a/src/libfreeswan/freeswan.h +++ /dev/null @@ -1,371 +0,0 @@ -#ifndef _FREESWAN_H -/* - * header file for FreeS/WAN library functions - * Copyright (C) 1998, 1999, 2000 Henry Spencer. - * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#define _FREESWAN_H /* seen it, no need to see it again */ - -# include -# include -# include - -# define DEBUG_NO_STATIC static - -#include -#include - -/* - * We assume header files have IPv6 (i.e. kernel version >= 2.1.0) - */ -#define NET_21 - -#ifndef IPPROTO_COMP -# define IPPROTO_COMP 108 -#endif /* !IPPROTO_COMP */ - -#ifndef IPPROTO_INT -# define IPPROTO_INT 61 -#endif /* !IPPROTO_INT */ - -#ifdef CONFIG_IPSEC_DEBUG -# define DEBUG_NO_STATIC -#else /* CONFIG_IPSEC_DEBUG */ -# define DEBUG_NO_STATIC static -#endif /* CONFIG_IPSEC_DEBUG */ - -#define ESPINUDP_WITH_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */ -#define ESPINUDP_WITH_NON_ESP 2 /* draft-ietf-ipsec-nat-t-ike-02 */ - -/* - * Basic data types for the address-handling functions. - * ip_address and ip_subnet are supposed to be opaque types; do not - * use their definitions directly, they are subject to change! - */ - -/* then the main types */ -typedef struct { - union { - struct sockaddr_in v4; - struct sockaddr_in6 v6; - } u; -} ip_address; -typedef struct { - ip_address addr; - int maskbits; -} ip_subnet; - -/* and the SA ID stuff */ -typedef u_int32_t ipsec_spi_t; -typedef struct { /* to identify an SA, we need: */ - ip_address dst; /* A. destination host */ - ipsec_spi_t spi; /* B. 32-bit SPI, assigned by dest. host */ -# define SPI_PASS 256 /* magic values... */ -# define SPI_DROP 257 /* ...for use... */ -# define SPI_REJECT 258 /* ...with SA_INT */ -# define SPI_HOLD 259 -# define SPI_TRAP 260 -# define SPI_TRAPSUBNET 261 - int proto; /* C. protocol */ -# define SA_ESP 50 /* IPPROTO_ESP */ -# define SA_AH 51 /* IPPROTO_AH */ -# define SA_IPIP 4 /* IPPROTO_IPIP */ -# define SA_COMP 108 /* IPPROTO_COMP */ -# define SA_INT 61 /* IANA reserved for internal use */ -} ip_said; -struct sa_id { /* old v4-only version */ - struct in_addr dst; - ipsec_spi_t spi; - int proto; -}; - -/* misc */ -struct prng { /* pseudo-random-number-generator guts */ - unsigned char sbox[256]; - int i, j; - unsigned long count; -}; - - -/* - * definitions for user space, taken from freeswan/ipsec_sa.h - */ -typedef uint32_t IPsecSAref_t; - -#define IPSEC_SA_REF_TABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH) - -#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t)) - -#define IPsecSAref2NFmark(x) ((x) << (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH)) -#define NFmark2IPsecSAref(x) ((x) >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH)) - -#define IPSEC_SAREF_NULL (~((IPsecSAref_t)0)) - -/* GCC magic for use in function definitions! */ -#ifdef GCC_LINT -# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1))) -# define NEVER_RETURNS __attribute__ ((noreturn)) -# define UNUSED __attribute__ ((unused)) -# define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */ -#else -# define PRINTF_LIKE(n) /* ignore */ -# define NEVER_RETURNS /* ignore */ -# define UNUSED /* ignore */ -# define BLANK_FORMAT "" -#endif - - - - - -/* - * new IPv6-compatible functions - */ - -/* text conversions */ -err_t ttoul(const char *src, size_t srclen, int format, unsigned long *dst); -size_t ultot(unsigned long src, int format, char *buf, size_t buflen); -#define ULTOT_BUF (22+1) /* holds 64 bits in octal */ -err_t ttoaddr(const char *src, size_t srclen, int af, ip_address *dst); -err_t tnatoaddr(const char *src, size_t srclen, int af, ip_address *dst); -size_t addrtot(const ip_address *src, int format, char *buf, size_t buflen); -/* RFC 1886 old IPv6 reverse-lookup format is the bulkiest */ -#define ADDRTOT_BUF (32*2 + 3 + 1 + 3 + 1 + 1) -err_t ttosubnet(const char *src, size_t srclen, int af, ip_subnet *dst); -size_t subnettot(const ip_subnet *src, int format, char *buf, size_t buflen); -#define SUBNETTOT_BUF (ADDRTOT_BUF + 1 + 3) -err_t ttosa(const char *src, size_t srclen, ip_said *dst); -size_t satot(const ip_said *src, int format, char *bufptr, size_t buflen); -#define SATOT_BUF (5 + ULTOA_BUF + 1 + ADDRTOT_BUF) -err_t ttodata(const char *src, size_t srclen, int base, char *buf, - size_t buflen, size_t *needed); -err_t ttodatav(const char *src, size_t srclen, int base, - char *buf, size_t buflen, size_t *needed, - char *errp, size_t errlen, unsigned int flags); -#define TTODATAV_BUF 40 /* ttodatav's largest non-literal message */ -#define TTODATAV_IGNORESPACE (1<<1) /* ignore spaces in base64 encodings*/ -#define TTODATAV_SPACECOUNTS 0 /* do not ignore spaces in base64 */ - -size_t datatot(const char *src, size_t srclen, int format, char *buf, - size_t buflen); -err_t ttoprotoport(char *src, size_t src_len, u_int8_t *proto, u_int16_t *port, - bool *has_port_wildcard); - -/* initializations */ -void initsaid(const ip_address *addr, ipsec_spi_t spi, int proto, ip_said *dst); -err_t loopbackaddr(int af, ip_address *dst); -err_t unspecaddr(int af, ip_address *dst); -err_t anyaddr(int af, ip_address *dst); -err_t initaddr(const unsigned char *src, size_t srclen, int af, ip_address *dst); -err_t initsubnet(const ip_address *addr, int maskbits, int clash, ip_subnet *dst); -err_t addrtosubnet(const ip_address *addr, ip_subnet *dst); - -/* misc. conversions and related */ -err_t rangetosubnet(const ip_address *from, const ip_address *to, ip_subnet *dst); -int addrtypeof(const ip_address *src); -int subnettypeof(const ip_subnet *src); -size_t addrlenof(const ip_address *src); -size_t addrbytesptr(const ip_address *src, const unsigned char **dst); -size_t addrbytesof(const ip_address *src, unsigned char *dst, size_t dstlen); -int masktocount(const ip_address *src); -void networkof(const ip_subnet *src, ip_address *dst); -void maskof(const ip_subnet *src, ip_address *dst); - -/* tests */ -int sameaddr(const ip_address *a, const ip_address *b); -int addrcmp(const ip_address *a, const ip_address *b); -int samesubnet(const ip_subnet *a, const ip_subnet *b); -int addrinsubnet(const ip_address *a, const ip_subnet *s); -int subnetinsubnet(const ip_subnet *a, const ip_subnet *b); -int subnetishost(const ip_subnet *s); -int samesaid(const ip_said *a, const ip_said *b); -int sameaddrtype(const ip_address *a, const ip_address *b); -int samesubnettype(const ip_subnet *a, const ip_subnet *b); -int isanyaddr(const ip_address *src); -int isunspecaddr(const ip_address *src); -int isloopbackaddr(const ip_address *src); - -/* low-level grot */ -int portof(const ip_address *src); -void setportof(int port, ip_address *dst); -struct sockaddr *sockaddrof(ip_address *src); -size_t sockaddrlenof(const ip_address *src); - -/* odds and ends */ -const char **ipsec_copyright_notice(void); - -const char *dns_string_rr(int rr, char *buf, int bufsize); -const char *dns_string_datetime(time_t seconds, - char *buf, - int bufsize); - - -/* - * old functions, to be deleted eventually - */ - -/* unsigned long */ -const char * /* NULL for success, else string literal */ -atoul( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - int base, /* 0 means figure it out */ - unsigned long *resultp -); -size_t /* space needed for full conversion */ -ultoa( - unsigned long n, - int base, - char *dst, - size_t dstlen -); -#define ULTOA_BUF 21 /* just large enough for largest result, */ - /* assuming 64-bit unsigned long! */ - -/* Internet addresses */ -const char * /* NULL for success, else string literal */ -atoaddr( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - struct in_addr *addr -); -size_t /* space needed for full conversion */ -addrtoa( - struct in_addr addr, - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); -#define ADDRTOA_BUF 16 /* just large enough for largest result */ - -/* subnets */ -const char * /* NULL for success, else string literal */ -atosubnet( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - struct in_addr *addr, - struct in_addr *mask -); -size_t /* space needed for full conversion */ -subnettoa( - struct in_addr addr, - struct in_addr mask, - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); -#define SUBNETTOA_BUF 32 /* large enough for worst case result */ - -/* ranges */ -const char * /* NULL for success, else string literal */ -atoasr( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - char *type, /* 'a', 's', 'r' */ - struct in_addr *addrs /* two-element array */ -); -size_t /* space needed for full conversion */ -rangetoa( - struct in_addr *addrs, /* two-element array */ - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); -#define RANGETOA_BUF 34 /* large enough for worst case result */ - -/* generic data, e.g. keys */ -const char * /* NULL for success, else string literal */ -atobytes( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - char *dst, - size_t dstlen, - size_t *lenp /* NULL means don't bother telling me */ -); -size_t /* 0 failure, else true size */ -bytestoa( - const char *src, - size_t srclen, - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); - -/* old versions of generic-data functions; deprecated */ -size_t /* 0 failure, else true size */ -atodata( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - char *dst, - size_t dstlen -); -size_t /* 0 failure, else true size */ -datatoa( - const char *src, - size_t srclen, - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); - -/* part extraction and special addresses */ -struct in_addr -subnetof( - struct in_addr addr, - struct in_addr mask -); -struct in_addr -hostof( - struct in_addr addr, - struct in_addr mask -); -struct in_addr -broadcastof( - struct in_addr addr, - struct in_addr mask -); - -/* mask handling */ -int -goodmask( - struct in_addr mask -); -int -masktobits( - struct in_addr mask -); -struct in_addr -bitstomask( - int n -); - -/* - * Debugging levels for pfkey_lib_debug - */ -#define PF_KEY_DEBUG_PARSE_NONE 0 -#define PF_KEY_DEBUG_PARSE_PROBLEM 1 -#define PF_KEY_DEBUG_PARSE_STRUCT 2 -#define PF_KEY_DEBUG_PARSE_FLOW 4 -#define PF_KEY_DEBUG_PARSE_MAX 7 - -extern unsigned int pfkey_lib_debug; /* bits selecting what to report */ - -/* - * pluto and lwdnsq need to know the maximum size of the commands to, - * and replies from lwdnsq. - */ - -#define LWDNSQ_CMDBUF_LEN 1024 -#define LWDNSQ_RESULT_LEN_MAX 4096 - -#endif /* _FREESWAN_H */ diff --git a/src/libfreeswan/goodmask.3 b/src/libfreeswan/goodmask.3 deleted file mode 100644 index b76d431ca..000000000 --- a/src/libfreeswan/goodmask.3 +++ /dev/null @@ -1,56 +0,0 @@ -.TH IPSEC_GOODMASK 3 "11 June 2001" -.SH NAME -ipsec goodmask \- is this Internet subnet mask a valid one? -.br -ipsec masktobits \- convert Internet subnet mask to bit count -.br -ipsec bitstomask \- convert bit count to Internet subnet mask -.SH SYNOPSIS -.B "#include -.sp -.B "int goodmask(struct in_addr mask);" -.br -.B "int masktobits(struct in_addr mask);" -.br -.B "struct in_addr bitstomask(int n);" -.SH DESCRIPTION -These functions are obsolete; -see -.IR ipsec_masktocount (3) -for a partial replacement. -.PP -.I Goodmask -reports whether the subnet -.I mask -is a valid one, -i.e. consists of a (possibly empty) sequence of -.BR 1 s -followed by a (possibly empty) sequence of -.BR 0 s. -.I Masktobits -takes a (valid) subnet mask and returns the number of -.B 1 -bits in it. -.I Bitstomask -reverses this, -returning the subnet mask corresponding to bit count -.IR n . -.PP -All masks are in network byte order. -.SH SEE ALSO -inet(3), ipsec_atosubnet(3) -.SH DIAGNOSTICS -.I Masktobits -returns -.B \-1 -for an invalid mask. -.I Bitstomask -returns an all-zeros mask for a negative or out-of-range -.IR n . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The error-reporting convention of -.I bitstomask -is less than ideal; -zero is sometimes a legitimate mask. diff --git a/src/libfreeswan/goodmask.c b/src/libfreeswan/goodmask.c deleted file mode 100644 index 66edae20f..000000000 --- a/src/libfreeswan/goodmask.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * minor utilities for subnet-mask manipulation - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - goodmask - is this a good (^1*0*$) subnet mask? - * You are not expected to understand this. See Henry S. Warren Jr, - * "Functions realizable with word-parallel logical and two's-complement - * addition instructions", CACM 20.6 (June 1977), p.439. - */ -int /* predicate */ -goodmask(mask) -struct in_addr mask; -{ - unsigned long x = ntohl(mask.s_addr); - /* clear rightmost contiguous string of 1-bits */ -# define CRCS1B(x) (((x|(x-1))+1)&x) -# define TOPBIT (1UL << 31) - - /* either zero, or has one string of 1-bits which is left-justified */ - if (x == 0 || (CRCS1B(x) == 0 && (x&TOPBIT))) - return 1; - return 0; -} - -/* - - masktobits - how many bits in this mask? - * The algorithm is essentially a binary search, but highly optimized - * for this particular task. - */ -int /* -1 means !goodmask() */ -masktobits(mask) -struct in_addr mask; -{ - unsigned long m = ntohl(mask.s_addr); - int masklen; - - if (!goodmask(mask)) - return -1; - - if (m&0x00000001UL) - return 32; - masklen = 0; - if (m&(0x0000ffffUL<<1)) { /* <<1 for 1-origin numbering */ - masklen |= 0x10; - m <<= 16; - } - if (m&(0x00ff0000UL<<1)) { - masklen |= 0x08; - m <<= 8; - } - if (m&(0x0f000000UL<<1)) { - masklen |= 0x04; - m <<= 4; - } - if (m&(0x30000000UL<<1)) { - masklen |= 0x02; - m <<= 2; - } - if (m&(0x40000000UL<<1)) - masklen |= 0x01; - - return masklen; -} - -/* - - bitstomask - return a mask with this many high bits on - */ -struct in_addr -bitstomask(n) -int n; -{ - struct in_addr result; - - if (n > 0 && n <= ABITS) - result.s_addr = htonl(~((1UL << (ABITS - n)) - 1)); - else if (n == 0) - result.s_addr = 0; - else - result.s_addr = 0; /* best error report we can do */ - return result; -} diff --git a/src/libfreeswan/initaddr.3 b/src/libfreeswan/initaddr.3 deleted file mode 100644 index 071e507aa..000000000 --- a/src/libfreeswan/initaddr.3 +++ /dev/null @@ -1,128 +0,0 @@ -.TH IPSEC_INITADDR 3 "11 Sept 2000" -.SH NAME -ipsec initaddr \- initialize an ip_address -.br -ipsec addrtypeof \- get address type of an ip_address -.br -ipsec addrlenof \- get length of address within an ip_address -.br -ipsec addrbytesof \- get copy of address within an ip_address -.br -ipsec addrbytesptr \- get pointer to address within an ip_address -.SH SYNOPSIS -.B "#include " -.sp -.B "const char *initaddr(const char *src, size_t srclen," -.ti +1c -.B "int af, ip_address *dst);" -.br -.B "int addrtypeof(const ip_address *src);" -.br -.B "size_t addrlenof(const ip_address *src);" -.br -.B "size_t addrbytesof(const ip_address *src," -.ti +1c -.B "unsigned char *dst, size_t dstlen);" -.br -.B "size_t addrbytesptr(const ip_address *src," -.ti +1c -.B "const unsigned char **dst);" -.SH DESCRIPTION -The -.B -library uses an internal type -.I ip_address -to contain one of the (currently two) types of IP address. -These functions provide basic tools for creating and examining this type. -.PP -.I Initaddr -initializes a variable -.I *dst -of type -.I ip_address -from an address -(in network byte order, -indicated by a pointer -.I src -and a length -.IR srclen ) -and an address family -.I af -(typically -.B AF_INET -or -.BR AF_INET6 ). -The length must be consistent with the address family. -.PP -.I Addrtypeof -returns the address type of an address, -normally -.B AF_INET -or -.BR AF_INET6 . -(The -.B -header file arranges to include the necessary headers for these -names to be known.) -.PP -.I Addrlenof -returns the size (in bytes) of the address within an -.IR ip_address , -to permit storage allocation etc. -.PP -.I Addrbytesof -copies the address within the -.I ip_address -.I src -to the buffer indicated by the pointer -.I dst -and the length -.IR dstlen , -and returns the address length (in bytes). -If the address will not fit, -as many bytes as will fit are copied; -the returned length is still the full length. -It is the caller's responsibility to check the -returned value to ensure that there was enough room. -.PP -.I Addrbytesptr -sets -.I *dst -to a pointer to the internal address within the -.IR ip_address , -and returns the address length (in bytes). -If -.I dst -is -.BR NULL , -it just returns the address length. -The pointer points to -.B const -to discourage misuse. -.PP -.I Initaddr -returns -.B NULL -for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.PP -The functions which return -.I size_t -return -.B 0 -for a failure. -.SH SEE ALSO -inet(3), ipsec_ttoaddr(3) -.SH DIAGNOSTICS -An unknown address family is a fatal error for any of these functions -except -.IR addrtypeof . -An address-size mismatch is a fatal error for -.IR initaddr . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -.I Addrtypeof -should probably have been named -.IR addrfamilyof . diff --git a/src/libfreeswan/initaddr.c b/src/libfreeswan/initaddr.c deleted file mode 100644 index c84006f47..000000000 --- a/src/libfreeswan/initaddr.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * initialize address structure - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - - initaddr - initialize ip_address from bytes - */ -err_t /* NULL for success, else string literal */ -initaddr(src, srclen, af, dst) -const unsigned char *src; -size_t srclen; -int af; /* address family */ -ip_address *dst; -{ - switch (af) { - case AF_INET: - if (srclen != 4) - return "IPv4 address must be exactly 4 bytes"; - dst->u.v4.sin_family = af; - dst->u.v4.sin_port = 0; /* unused */ - memcpy((char *)&dst->u.v4.sin_addr.s_addr, src, srclen); - break; - case AF_INET6: - if (srclen != 16) - return "IPv6 address must be exactly 16 bytes"; - dst->u.v6.sin6_family = af; - dst->u.v6.sin6_flowinfo = 0; /* unused */ - dst->u.v6.sin6_port = 0; /* unused */ - memcpy((char *)&dst->u.v6.sin6_addr, src, srclen); - break; - default: - return "unknown address family in initaddr"; - break; - } - return NULL; -} diff --git a/src/libfreeswan/initsaid.c b/src/libfreeswan/initsaid.c deleted file mode 100644 index 4e4bc9a35..000000000 --- a/src/libfreeswan/initsaid.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * initialize SA ID structure - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - initsaid - initialize SA ID from bits - */ -void -initsaid(addr, spi, proto, dst) -const ip_address *addr; -ipsec_spi_t spi; -int proto; -ip_said *dst; -{ - dst->dst = *addr; - dst->spi = spi; - dst->proto = proto; -} diff --git a/src/libfreeswan/initsubnet.3 b/src/libfreeswan/initsubnet.3 deleted file mode 100644 index 3545fd426..000000000 --- a/src/libfreeswan/initsubnet.3 +++ /dev/null @@ -1,136 +0,0 @@ -.TH IPSEC_INITSUBNET 3 "12 March 2002" -.SH NAME -ipsec initsubnet \- initialize an ip_subnet -.br -ipsec addrtosubnet \- initialize a singleton ip_subnet -.br -ipsec subnettypeof \- get address type of an ip_subnet -.br -ipsec masktocount \- convert subnet mask to bit count -.br -ipsec networkof \- get base address of an ip_subnet -.br -ipsec maskof \- get subnet mask of an ip_subnet -.SH SYNOPSIS -.B "#include " -.sp -.B "const char *initsubnet(const ip_address *addr," -.ti +1c -.B "int maskbits, int clash, ip_subnet *dst);" -.br -.B "const char *addrtosubnet(const ip_address *addr," -.ti +1c -.B "ip_subnet *dst);" -.sp -.B "int subnettypeof(const ip_subnet *src);" -.br -.B "int masktocount(const ip_address *src);" -.br -.B "void networkof(const ip_subnet *src, ip_address *dst);" -.br -.B "void maskof(const ip_subnet *src, ip_address *dst);" -.SH DESCRIPTION -The -.B -library uses an internal type -.I ip_subnet -to contain a description of an IP subnet -(base address plus mask). -These functions provide basic tools for creating and examining this type. -.PP -.I Initsubnet -initializes a variable -.I *dst -of type -.I ip_subnet -from a base address and -a count of mask bits. -The -.I clash -parameter specifies what to do if the base address includes -.B 1 -bits outside the prefix specified by the mask -(that is, in the ``host number'' part of the address): -.RS -.IP '0' 5 -zero out host-number bits -.IP 'x' -non-zero host-number bits are an error -.RE -.PP -.I Initsubnet -returns -.B NULL -for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.PP -.I Addrtosubnet -initializes an -.I ip_subnet -variable -.I *dst -to a ``singleton subnet'' containing the single address -.IR *addr . -It returns -.B NULL -for success and -a pointer to a string-literal error message for failure. -.PP -.I Subnettypeof -returns the address type of a subnet, -normally -.B AF_INET -or -.BR AF_INET6 . -(The -.B -header file arranges to include the necessary headers for these -names to be known.) -.PP -.I Masktocount -converts a subnet mask, expressed as an address, to a bit count -suitable for use with -.IR initsubnet . -It returns -.B \-1 -for error; see DIAGNOSTICS. -.PP -.I Networkof -fills in -.I *dst -with the base address of subnet -.IR src . -.PP -.I Maskof -fills in -.I *dst -with the subnet mask of subnet -.IR src , -expressed as an address. -.SH SEE ALSO -inet(3), ipsec_ttosubnet(3), ipsec_rangetosubnet(3) -.SH DIAGNOSTICS -Fatal errors in -.I initsubnet -are: -unknown address family; -unknown -.I clash -value; -impossible mask bit count; -non-zero host-number bits and -.I clash -is -.BR 'x' . -Fatal errors in -.I addrtosubnet -are: -unknown address family. -Fatal errors in -.I masktocount -are: -unknown address family; -mask bits not contiguous. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. diff --git a/src/libfreeswan/initsubnet.c b/src/libfreeswan/initsubnet.c deleted file mode 100644 index 27faddabc..000000000 --- a/src/libfreeswan/initsubnet.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * initialize subnet structure - * Copyright (C) 2000, 2002 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - initsubnet - initialize ip_subnet from address and count - * - * The only hard part is checking for host-part bits turned on. - */ -err_t /* NULL for success, else string literal */ -initsubnet(addr, count, clash, dst) -const ip_address *addr; -int count; -int clash; /* '0' zero host-part bits, 'x' die on them */ -ip_subnet *dst; -{ - unsigned char *p; - int n; - int c; - unsigned m; - int die; - - dst->addr = *addr; - n = addrbytesptr(&dst->addr, (const unsigned char **)&p); - if (n == 0) - return "unknown address family"; - - switch (clash) { - case '0': - die = 0; - break; - case 'x': - die = 1; - break; - default: - return "unknown clash-control value in initsubnet"; - break; - } - - c = count / 8; - if (c > n) - return "impossible mask count"; - p += c; - n -= c; - - m = 0xff; - c = count % 8; - if (n > 0 && c != 0) /* partial byte */ - m >>= c; - for (; n > 0; n--) { - if ((*p & m) != 0) { - if (die) - return "improper subnet, host-part bits on"; - *p &= ~m; - } - m = 0xff; - p++; - } - - dst->maskbits = count; - return NULL; -} - -/* - - addrtosubnet - initialize ip_subnet from a single address - */ -err_t /* NULL for success, else string literal */ -addrtosubnet(addr, dst) -const ip_address *addr; -ip_subnet *dst; -{ - int n; - - dst->addr = *addr; - n = addrbytesptr(&dst->addr, (const unsigned char **)NULL); - if (n == 0) - return "unknown address family"; - dst->maskbits = n*8; - return NULL; -} diff --git a/src/libfreeswan/internal.h b/src/libfreeswan/internal.h deleted file mode 100644 index 832c8a53d..000000000 --- a/src/libfreeswan/internal.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * internal definitions for use within the library; do not export! - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ - -#ifndef ABITS -#define ABITS 32 /* bits in an IPv4 address */ -#endif - -/* case-independent ASCII character equality comparison */ -#define CIEQ(c1, c2) ( ((c1)&~040) == ((c2)&~040) ) - -/* syntax for passthrough SA */ -#ifndef PASSTHROUGHNAME -#define PASSTHROUGHNAME "%passthrough" -#define PASSTHROUGH4NAME "%passthrough4" -#define PASSTHROUGH6NAME "%passthrough6" -#define PASSTHROUGHIS "tun0@0.0.0.0" -#define PASSTHROUGH4IS "tun0@0.0.0.0" -#define PASSTHROUGH6IS "tun0@::" -#define PASSTHROUGHTYPE "tun" -#define PASSTHROUGHSPI 0 -#define PASSTHROUGHDST 0 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#define MALLOC(n) malloc(n) -#define FREE(p) free(p) - diff --git a/src/libfreeswan/ipsec_param.h b/src/libfreeswan/ipsec_param.h deleted file mode 100644 index 93426b8ee..000000000 --- a/src/libfreeswan/ipsec_param.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * @(#) FreeSWAN tunable paramaters - * - * Copyright (C) 2001 Richard Guy Briggs - * and Michael Richardson - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * This file provides a set of #define's which may be tuned by various - * people/configurations. It keeps all compile-time tunables in one place. - * - * This file should be included before all other IPsec kernel-only files. - * - */ - -#ifndef _IPSEC_PARAM_H_ - -/* - * This is for the SA reference table. This number is related to the - * maximum number of SAs that KLIPS can concurrently deal with, plus enough - * space for keeping expired SAs around. - * - * TABLE_MAX_WIDTH is the number of bits that we will use. - * MAIN_TABLE_WIDTH is the number of bits used for the primary index table. - * - */ -#ifndef IPSEC_SA_REF_TABLE_IDX_WIDTH -# define IPSEC_SA_REF_TABLE_IDX_WIDTH 16 -#endif - -#ifndef IPSEC_SA_REF_MAINTABLE_IDX_WIDTH -# define IPSEC_SA_REF_MAINTABLE_IDX_WIDTH 4 -#endif - -#ifndef IPSEC_SA_REF_FREELIST_NUM_ENTRIES -# define IPSEC_SA_REF_FREELIST_NUM_ENTRIES 256 -#endif - -#ifndef IPSEC_SA_REF_CODE -# define IPSEC_SA_REF_CODE 1 -#endif - -#define _IPSEC_PARAM_H_ -#endif /* _IPSEC_PARAM_H_ */ diff --git a/src/libfreeswan/pfkey.h b/src/libfreeswan/pfkey.h deleted file mode 100644 index 993678c8b..000000000 --- a/src/libfreeswan/pfkey.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * FreeS/WAN specific PF_KEY headers - * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef __NET_IPSEC_PF_KEY_H -#define __NET_IPSEC_PF_KEY_H - -extern void (*pfkey_debug_func)(const char *message, ...); - -extern uint8_t satype2proto(uint8_t satype); -extern uint8_t proto2satype(uint8_t proto); -extern char* satype2name(uint8_t satype); -extern char* proto2name(uint8_t proto); - -struct key_opt -{ - uint32_t key_pid; /* process ID */ - struct sock *sk; -}; - -#define key_pid(sk) ((struct key_opt*)&((sk)->protinfo))->key_pid - -#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t)) -#define BITS_PER_OCTET 8 -#define OCTETBITS 8 -#define PFKEYBITS 64 -#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */ -#define ALIGN_N(x,y) (DIVUP(x,y) * y) /* align on y boundary */ - -#define PFKEYv2_MAX_MSGSIZE 4096 - -/* - * PF_KEYv2 permitted and required extensions in and out bitmaps - */ -struct pf_key_ext_parsers_def { - int (*parser)(struct sadb_ext*); - char *parser_name; -}; - - -extern unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/]; -#define EXT_BITS_IN 0 -#define EXT_BITS_OUT 1 -#define EXT_BITS_PERM 0 -#define EXT_BITS_REQ 1 - -extern void pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]); -extern void pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]); -extern void pfkey_msg_free(struct sadb_msg **pfkey_msg); - -extern int pfkey_msg_parse(struct sadb_msg *pfkey_msg, - struct pf_key_ext_parsers_def *ext_parsers[], - struct sadb_ext **extensions, - int dir); - -/* - * PF_KEYv2 build function prototypes - */ - -int -pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext, - uint8_t msg_type, - uint8_t satype, - uint8_t msg_errno, - uint32_t seq, - uint32_t pid); - -int -pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t spi, /* in network order */ - uint8_t replay_window, - uint8_t sa_state, - uint8_t auth, - uint8_t encrypt, - uint32_t flags, - uint32_t/*IPsecSAref_t*/ ref); - -int -pfkey_sa_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t spi, /* in network order */ - uint8_t replay_window, - uint8_t sa_state, - uint8_t auth, - uint8_t encrypt, - uint32_t flags); - -int -pfkey_lifetime_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t allocations, - uint64_t bytes, - uint64_t addtime, - uint64_t usetime, - uint32_t packets); - -int -pfkey_address_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint8_t proto, - uint8_t prefixlen, - struct sockaddr* address); - -int -pfkey_key_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t key_bits, - char* key); - -int -pfkey_ident_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t ident_type, - uint64_t ident_id, - uint8_t ident_len, - char* ident_string); - -int -pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext, - uint8_t type); -int -pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t port); - -int -pfkey_sens_build(struct sadb_ext** pfkey_ext, - uint32_t dpd, - uint8_t sens_level, - uint8_t sens_len, - uint64_t* sens_bitmap, - uint8_t integ_level, - uint8_t integ_len, - uint64_t* integ_bitmap); - -int -pfkey_x_protocol_build(struct sadb_ext **, uint8_t); - - -int -pfkey_prop_build(struct sadb_ext** pfkey_ext, - uint8_t replay, - unsigned int comb_num, - struct sadb_comb* comb); - -int -pfkey_supported_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - unsigned int alg_num, - struct sadb_alg* alg); - -int -pfkey_spirange_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint32_t min, - uint32_t max); - -int -pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext); - -int -pfkey_x_satype_build(struct sadb_ext** pfkey_ext, - uint8_t satype); - -int -pfkey_x_debug_build(struct sadb_ext** pfkey_ext, - uint32_t tunnel, - uint32_t netlink, - uint32_t xform, - uint32_t eroute, - uint32_t spi, - uint32_t radij, - uint32_t esp, - uint32_t ah, - uint32_t rcv, - uint32_t pfkey, - uint32_t ipcomp, - uint32_t verbose); - -int -pfkey_msg_build(struct sadb_msg** pfkey_msg, - struct sadb_ext* extensions[], - int dir); - -/* in pfkey_v2_debug.c - routines to decode numbers -> strings */ -const char * -pfkey_v2_sadb_ext_string(int extnum); - -const char * -pfkey_v2_sadb_type_string(int sadb_type); - - -#endif /* __NET_IPSEC_PF_KEY_H */ diff --git a/src/libfreeswan/pfkey_v2_build.c b/src/libfreeswan/pfkey_v2_build.c deleted file mode 100644 index c0bb369cb..000000000 --- a/src/libfreeswan/pfkey_v2_build.c +++ /dev/null @@ -1,1388 +0,0 @@ -/* - * RFC2367 PF_KEYv2 Key management API message parser - * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Template from klips/net/ipsec/ipsec/ipsec_parser.c. - */ - -char pfkey_v2_build_c_version[] = ""; - -# include -# include -# include -# include -# include /* memset */ - -# include -unsigned int pfkey_lib_debug = 0; - -void (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1); - -#define DEBUGGING(args...) if(pfkey_lib_debug) { \ - if(pfkey_debug_func != NULL) { \ - (*pfkey_debug_func)("pfkey_lib_debug:" args); \ - } else { \ - printf("pfkey_lib_debug:" args); \ - } } -# define MALLOC(size) malloc(size) -# define FREE(obj) free(obj) - -#include -#include - -#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0) - -void -pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - int i; - - for (i = 0; i != SADB_EXT_MAX + 1; i++) { - extensions[i] = NULL; - } -} - -void -pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - int i; - - if (!extensions) { - return; - } - - if (extensions[0]) { - memset(extensions[0], 0, sizeof(struct sadb_msg)); - FREE(extensions[0]); - extensions[0] = NULL; - } - - for (i = 1; i != SADB_EXT_MAX + 1; i++) { - if(extensions[i]) { - memset(extensions[i], 0, extensions[i]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN); - FREE(extensions[i]); - extensions[i] = NULL; - } - } -} - -void -pfkey_msg_free(struct sadb_msg **pfkey_msg) -{ - if (*pfkey_msg) { - memset(*pfkey_msg, 0, (*pfkey_msg)->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); - FREE(*pfkey_msg); - *pfkey_msg = NULL; - } -} - -/* Default extension builders taken from the KLIPS code */ - -int -pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext, - uint8_t msg_type, - uint8_t satype, - uint8_t msg_errno, - uint32_t seq, - uint32_t pid) -{ - int error = 0; - struct sadb_msg *pfkey_msg = (struct sadb_msg *)*pfkey_ext; - - DEBUGGING( - "pfkey_msg_hdr_build:\n"); - DEBUGGING( - "pfkey_msg_hdr_build: " - "on_entry &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n", - &pfkey_ext, - pfkey_ext, - *pfkey_ext); - /* sanity checks... */ - if (pfkey_msg) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "why is pfkey_msg already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (!msg_type) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "msg type not set, must be non-zero..\n"); - SENDERR(EINVAL); - } - - if (msg_type > SADB_MAX) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "msg type too large:%d.\n", - msg_type); - SENDERR(EINVAL); - } - - if (satype > SADB_SATYPE_MAX) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "satype %d > max %d\n", - satype, SADB_SATYPE_MAX); - SENDERR(EINVAL); - } - - pfkey_msg = (struct sadb_msg*)MALLOC(sizeof(struct sadb_msg)); - *pfkey_ext = (struct sadb_ext*)pfkey_msg; - - if (pfkey_msg == NULL) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_msg, 0, sizeof(struct sadb_msg)); - - pfkey_msg->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN; - - pfkey_msg->sadb_msg_type = msg_type; - pfkey_msg->sadb_msg_satype = satype; - - pfkey_msg->sadb_msg_version = PF_KEY_V2; - pfkey_msg->sadb_msg_errno = msg_errno; - pfkey_msg->sadb_msg_reserved = 0; - pfkey_msg->sadb_msg_seq = seq; - pfkey_msg->sadb_msg_pid = pid; - DEBUGGING( - "pfkey_msg_hdr_build: " - "on_exit &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n", - &pfkey_ext, - pfkey_ext, - *pfkey_ext); -errlab: - return error; -} - -int -pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t spi, - uint8_t replay_window, - uint8_t sa_state, - uint8_t auth, - uint8_t encrypt, - uint32_t flags, - uint32_t/*IPsecSAref_t*/ ref) -{ - int error = 0; - struct sadb_sa *pfkey_sa = (struct sadb_sa *)*pfkey_ext; - - DEBUGGING( - "pfkey_sa_build: " - "spi=%08x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n", - ntohl(spi), /* in network order */ - replay_window, - sa_state, - auth, - encrypt, - flags); - /* sanity checks... */ - if (pfkey_sa) { - DEBUGGING( - "pfkey_sa_build: " - "why is pfkey_sa already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (exttype != SADB_EXT_SA - && exttype != SADB_X_EXT_SA2) { - DEBUGGING( - "pfkey_sa_build: " - "invalid exttype=%d.\n", - exttype); - SENDERR(EINVAL); - } - - if (replay_window > 64) { - DEBUGGING( - "pfkey_sa_build: " - "replay window size: %d -- must be 0 <= size <= 64\n", - replay_window); - SENDERR(EINVAL); - } - - if (auth > SADB_AALG_MAX) { - DEBUGGING( - "pfkey_sa_build: " - "auth=%d > SADB_AALG_MAX=%d.\n", - auth, - SADB_AALG_MAX); - SENDERR(EINVAL); - } - - if (encrypt > SADB_EALG_MAX) { - DEBUGGING( - "pfkey_sa_build: " - "encrypt=%d > SADB_EALG_MAX=%d.\n", - encrypt, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - - if (sa_state > SADB_SASTATE_MAX) { - DEBUGGING( - "pfkey_sa_build: " - "sa_state=%d exceeds MAX=%d.\n", - sa_state, - SADB_SASTATE_MAX); - SENDERR(EINVAL); - } - - if (sa_state == SADB_SASTATE_DEAD) { - DEBUGGING( - "pfkey_sa_build: " - "sa_state=%d is DEAD=%d is not allowed.\n", - sa_state, - SADB_SASTATE_DEAD); - SENDERR(EINVAL); - } - - if ((IPSEC_SAREF_NULL != ref) && (ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) { - DEBUGGING( - "pfkey_sa_build: " - "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n", - ref, - IPSEC_SAREF_NULL, - IPSEC_SA_REF_TABLE_NUM_ENTRIES); - SENDERR(EINVAL); - } - - pfkey_sa = (struct sadb_sa*)MALLOC(sizeof(struct sadb_sa)); - *pfkey_ext = (struct sadb_ext*)pfkey_sa; - - if (pfkey_sa == NULL) { - DEBUGGING( - "pfkey_sa_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_sa, 0, sizeof(struct sadb_sa)); - - pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN; - pfkey_sa->sadb_sa_exttype = exttype; - pfkey_sa->sadb_sa_spi = spi; - pfkey_sa->sadb_sa_replay = replay_window; - pfkey_sa->sadb_sa_state = sa_state; - pfkey_sa->sadb_sa_auth = auth; - pfkey_sa->sadb_sa_encrypt = encrypt; - pfkey_sa->sadb_sa_flags = flags; - pfkey_sa->sadb_x_sa_ref = ref; - -errlab: - return error; -} - -int -pfkey_sa_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t spi, - uint8_t replay_window, - uint8_t sa_state, - uint8_t auth, - uint8_t encrypt, - uint32_t flags) -{ - return pfkey_sa_ref_build(pfkey_ext, - exttype, - spi, - replay_window, - sa_state, - auth, - encrypt, - flags, - IPSEC_SAREF_NULL); -} - -int -pfkey_lifetime_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t allocations, - uint64_t bytes, - uint64_t addtime, - uint64_t usetime, - uint32_t packets) -{ - int error = 0; - struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext; - - DEBUGGING( - "pfkey_lifetime_build:\n"); - /* sanity checks... */ - if (pfkey_lifetime) { - DEBUGGING( - "pfkey_lifetime_build: " - "why is pfkey_lifetime already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (exttype != SADB_EXT_LIFETIME_CURRENT - && exttype != SADB_EXT_LIFETIME_HARD - && exttype != SADB_EXT_LIFETIME_SOFT) { - DEBUGGING( - "pfkey_lifetime_build: " - "invalid exttype=%d.\n", - exttype); - SENDERR(EINVAL); - } - - pfkey_lifetime = (struct sadb_lifetime*)MALLOC(sizeof(struct sadb_lifetime)); - *pfkey_ext = (struct sadb_ext*)pfkey_lifetime; - - if (pfkey_lifetime == NULL) { - DEBUGGING( - "pfkey_lifetime_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_lifetime, 0, sizeof(struct sadb_lifetime)); - - pfkey_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN; - pfkey_lifetime->sadb_lifetime_exttype = exttype; - pfkey_lifetime->sadb_lifetime_allocations = allocations; - pfkey_lifetime->sadb_lifetime_bytes = bytes; - pfkey_lifetime->sadb_lifetime_addtime = addtime; - pfkey_lifetime->sadb_lifetime_usetime = usetime; - pfkey_lifetime->sadb_x_lifetime_packets = packets; - -errlab: - return error; -} - -int -pfkey_address_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint8_t proto, - uint8_t prefixlen, - struct sockaddr* address) -{ - int error = 0; - int saddr_len = 0; - char ipaddr_txt[ADDRTOT_BUF + 6/*extra for port number*/]; - struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext; - - DEBUGGING( - "pfkey_address_build: " - "exttype=%d proto=%d prefixlen=%d\n", - exttype, - proto, - prefixlen); - /* sanity checks... */ - if (pfkey_address) { - DEBUGGING( - "pfkey_address_build: " - "why is pfkey_address already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (!address) { - DEBUGGING("pfkey_address_build: " - "address is NULL\n"); - SENDERR(EINVAL); - } - - switch(exttype) { - case SADB_EXT_ADDRESS_SRC: - case SADB_EXT_ADDRESS_DST: - case SADB_EXT_ADDRESS_PROXY: - case SADB_X_EXT_ADDRESS_DST2: - case SADB_X_EXT_ADDRESS_SRC_FLOW: - case SADB_X_EXT_ADDRESS_DST_FLOW: - case SADB_X_EXT_ADDRESS_SRC_MASK: - case SADB_X_EXT_ADDRESS_DST_MASK: - case SADB_X_EXT_NAT_T_OA: - break; - default: - DEBUGGING( - "pfkey_address_build: " - "unrecognised ext_type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - switch (address->sa_family) { - case AF_INET: - DEBUGGING( - "pfkey_address_build: " - "found address family AF_INET.\n"); - saddr_len = sizeof(struct sockaddr_in); - sprintf(ipaddr_txt, "%d.%d.%d.%d:%d" - , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 0) & 0xFF - , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 8) & 0xFF - , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 16) & 0xFF - , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 24) & 0xFF - , ntohs(((struct sockaddr_in*)address)->sin_port)); - break; - case AF_INET6: - DEBUGGING( - "pfkey_address_build: " - "found address family AF_INET6.\n"); - saddr_len = sizeof(struct sockaddr_in6); - sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x-%x" - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[0]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[1]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[2]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[3]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[4]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[5]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[6]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[7]) - , ntohs(((struct sockaddr_in6*)address)->sin6_port)); - break; - default: - DEBUGGING( - "pfkey_address_build: " - "address->sa_family=%d not supported.\n", - address->sa_family); - SENDERR(EPFNOSUPPORT); - } - - DEBUGGING( - "pfkey_address_build: " - "found address=%s.\n", - ipaddr_txt); - if (prefixlen != 0) { - DEBUGGING( - "pfkey_address_build: " - "address prefixes not supported yet.\n"); - SENDERR(EAFNOSUPPORT); /* not supported yet */ - } - - pfkey_address = (struct sadb_address*) - MALLOC(ALIGN_N(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)); - *pfkey_ext = (struct sadb_ext*)pfkey_address; - - if (pfkey_address == NULL) { - DEBUGGING( - "pfkey_lifetime_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_address, - 0, - ALIGN_N(sizeof(struct sadb_address) + saddr_len, - IPSEC_PFKEYv2_ALIGN)); - - pfkey_address->sadb_address_len = DIVUP(sizeof(struct sadb_address) + saddr_len, - IPSEC_PFKEYv2_ALIGN); - - pfkey_address->sadb_address_exttype = exttype; - pfkey_address->sadb_address_proto = proto; - pfkey_address->sadb_address_prefixlen = prefixlen; - pfkey_address->sadb_address_reserved = 0; - - memcpy((char*)pfkey_address + sizeof(struct sadb_address), - address, - saddr_len); - -#if 0 - for (i = 0; i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) { - pfkey_address_s_ska.sin_zero[i] = 0; - } -#endif - DEBUGGING( - "pfkey_address_build: " - "successful.\n"); - - errlab: - return error; -} - -int -pfkey_key_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t key_bits, - char* key) -{ - int error = 0; - struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext; - - DEBUGGING( - "pfkey_key_build:\n"); - /* sanity checks... */ - if (pfkey_key) { - DEBUGGING( - "pfkey_key_build: " - "why is pfkey_key already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (!key_bits) { - DEBUGGING( - "pfkey_key_build: " - "key_bits is zero, it must be non-zero.\n"); - SENDERR(EINVAL); - } - - if ( !((exttype == SADB_EXT_KEY_AUTH) || (exttype == SADB_EXT_KEY_ENCRYPT))) { - DEBUGGING( - "pfkey_key_build: " - "unsupported extension type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - pfkey_key = (struct sadb_key*) - MALLOC(sizeof(struct sadb_key) + - DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN); - *pfkey_ext = (struct sadb_ext*)pfkey_key; - - if (pfkey_key == NULL) { - DEBUGGING( - "pfkey_key_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_key, - 0, - sizeof(struct sadb_key) + - DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN); - - pfkey_key->sadb_key_len = DIVUP(sizeof(struct sadb_key) * IPSEC_PFKEYv2_ALIGN + key_bits, - 64); - pfkey_key->sadb_key_exttype = exttype; - pfkey_key->sadb_key_bits = key_bits; - pfkey_key->sadb_key_reserved = 0; - memcpy((char*)pfkey_key + sizeof(struct sadb_key), - key, - DIVUP(key_bits, 8)); - -errlab: - return error; -} - -int -pfkey_ident_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t ident_type, - uint64_t ident_id, - uint8_t ident_len, - char* ident_string) -{ - int error = 0; - struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext; - int data_len = ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident); - - DEBUGGING( - "pfkey_ident_build:\n"); - /* sanity checks... */ - if (pfkey_ident) { - DEBUGGING( - "pfkey_ident_build: " - "why is pfkey_ident already pointing to something?\n"); - SENDERR(EINVAL); - } - - if ( !((exttype == SADB_EXT_IDENTITY_SRC) || - (exttype == SADB_EXT_IDENTITY_DST))) { - DEBUGGING( - "pfkey_ident_build: " - "unsupported extension type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - if (ident_type == SADB_IDENTTYPE_RESERVED) { - DEBUGGING( - "pfkey_ident_build: " - "ident_type must be non-zero.\n"); - SENDERR(EINVAL); - } - - if (ident_type > SADB_IDENTTYPE_MAX) { - DEBUGGING( - "pfkey_ident_build: " - "identtype=%d out of range.\n", - ident_type); - SENDERR(EINVAL); - } - - if ((ident_type == SADB_IDENTTYPE_PREFIX || - ident_type == SADB_IDENTTYPE_FQDN) && - !ident_string) { - DEBUGGING( - "pfkey_ident_build: " - "string required to allocate size of extension.\n"); - SENDERR(EINVAL); - } - -#if 0 - if (ident_type == SADB_IDENTTYPE_USERFQDN) { - } -#endif - - pfkey_ident = (struct sadb_ident*) - MALLOC(ident_len * IPSEC_PFKEYv2_ALIGN); - *pfkey_ext = (struct sadb_ext*)pfkey_ident; - - if (pfkey_ident == NULL) { - DEBUGGING( - "pfkey_ident_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_ident, 0, ident_len * IPSEC_PFKEYv2_ALIGN); - - pfkey_ident->sadb_ident_len = ident_len; - pfkey_ident->sadb_ident_exttype = exttype; - pfkey_ident->sadb_ident_type = ident_type; - pfkey_ident->sadb_ident_reserved = 0; - pfkey_ident->sadb_ident_id = ident_id; - memcpy((char*)pfkey_ident + sizeof(struct sadb_ident), - ident_string, - data_len); - -errlab: - return error; -} - -int -pfkey_sens_build(struct sadb_ext** pfkey_ext, - uint32_t dpd, - uint8_t sens_level, - uint8_t sens_len, - uint64_t* sens_bitmap, - uint8_t integ_level, - uint8_t integ_len, - uint64_t* integ_bitmap) -{ - int error = 0; - struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext; - int i; - uint64_t* bitmap; - - DEBUGGING( - "pfkey_sens_build:\n"); - /* sanity checks... */ - if (pfkey_sens) { - DEBUGGING( - "pfkey_sens_build: " - "why is pfkey_sens already pointing to something?\n"); - SENDERR(EINVAL); - } - - DEBUGGING( - "pfkey_sens_build: " - "Sorry, I can't build exttype=%d yet.\n", - (*pfkey_ext)->sadb_ext_type); - SENDERR(EINVAL); /* don't process these yet */ - - pfkey_sens = (struct sadb_sens*) - MALLOC(sizeof(struct sadb_sens) + - (sens_len + integ_len) * sizeof(uint64_t)); - *pfkey_ext = (struct sadb_ext*)pfkey_sens; - - if (pfkey_sens == NULL) { - DEBUGGING( - "pfkey_sens_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_sens, - 0, - sizeof(struct sadb_sens) + - (sens_len + integ_len) * sizeof(uint64_t)); - - pfkey_sens->sadb_sens_len = (sizeof(struct sadb_sens) + - (sens_len + integ_len) * sizeof(uint64_t)) / IPSEC_PFKEYv2_ALIGN; - pfkey_sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY; - pfkey_sens->sadb_sens_dpd = dpd; - pfkey_sens->sadb_sens_sens_level = sens_level; - pfkey_sens->sadb_sens_sens_len = sens_len; - pfkey_sens->sadb_sens_integ_level = integ_level; - pfkey_sens->sadb_sens_integ_len = integ_len; - pfkey_sens->sadb_sens_reserved = 0; - - bitmap = (uint64_t*)((char*)pfkey_ext + sizeof(struct sadb_sens)); - for (i = 0; i < sens_len; i++) { - *bitmap = sens_bitmap[i]; - bitmap++; - } - for (i = 0; i < integ_len; i++) { - *bitmap = integ_bitmap[i]; - bitmap++; - } - -errlab: - return error; -} - -int -pfkey_prop_build(struct sadb_ext** pfkey_ext, - uint8_t replay, - unsigned int comb_num, - struct sadb_comb* comb) -{ - int error = 0; - int i; - struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext; - struct sadb_comb *combp; - - DEBUGGING( - "pfkey_prop_build:\n"); - /* sanity checks... */ - if (pfkey_prop) { - DEBUGGING( - "pfkey_prop_build: " - "why is pfkey_prop already pointing to something?\n"); - SENDERR(EINVAL); - } - - pfkey_prop = (struct sadb_prop*) - MALLOC(sizeof(struct sadb_prop) + - comb_num * sizeof(struct sadb_comb)); - - *pfkey_ext = (struct sadb_ext*)pfkey_prop; - - if (pfkey_prop == NULL) { - DEBUGGING( - "pfkey_prop_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_prop, - 0, - sizeof(struct sadb_prop) + - comb_num * sizeof(struct sadb_comb)); - - pfkey_prop->sadb_prop_len = (sizeof(struct sadb_prop) + - comb_num * sizeof(struct sadb_comb)) / IPSEC_PFKEYv2_ALIGN; - - pfkey_prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; - pfkey_prop->sadb_prop_replay = replay; - - for (i=0; i<3; i++) { - pfkey_prop->sadb_prop_reserved[i] = 0; - } - - combp = (struct sadb_comb*)((char*)*pfkey_ext + sizeof(struct sadb_prop)); - for (i = 0; i < comb_num; i++) { - memcpy (combp, &(comb[i]), sizeof(struct sadb_comb)); - combp++; - } - -#if 0 - uint8_t sadb_comb_auth; - uint8_t sadb_comb_encrypt; - uint16_t sadb_comb_flags; - uint16_t sadb_comb_auth_minbits; - uint16_t sadb_comb_auth_maxbits; - uint16_t sadb_comb_encrypt_minbits; - uint16_t sadb_comb_encrypt_maxbits; - uint32_t sadb_comb_reserved; - uint32_t sadb_comb_soft_allocations; - uint32_t sadb_comb_hard_allocations; - uint64_t sadb_comb_soft_bytes; - uint64_t sadb_comb_hard_bytes; - uint64_t sadb_comb_soft_addtime; - uint64_t sadb_comb_hard_addtime; - uint64_t sadb_comb_soft_usetime; - uint64_t sadb_comb_hard_usetime; - uint32_t sadb_comb_soft_packets; - uint32_t sadb_comb_hard_packets; -#endif -errlab: - return error; -} - -int -pfkey_supported_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - unsigned int alg_num, - struct sadb_alg* alg) -{ - int error = 0; - unsigned int i; - struct sadb_supported *pfkey_supported = (struct sadb_supported *)*pfkey_ext; - struct sadb_alg *pfkey_alg; - - /* sanity checks... */ - if (pfkey_supported) { - DEBUGGING( - "pfkey_supported_build: " - "why is pfkey_supported already pointing to something?\n"); - SENDERR(EINVAL); - } - - if ( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) { - DEBUGGING( - "pfkey_supported_build: " - "unsupported extension type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - pfkey_supported = (struct sadb_supported*) - MALLOC(sizeof(struct sadb_supported) + - alg_num * sizeof(struct sadb_alg)); - - *pfkey_ext = (struct sadb_ext*)pfkey_supported; - - if (pfkey_supported == NULL) { - DEBUGGING( - "pfkey_supported_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_supported, - 0, - sizeof(struct sadb_supported) + - alg_num * - sizeof(struct sadb_alg)); - - pfkey_supported->sadb_supported_len = (sizeof(struct sadb_supported) + - alg_num * - sizeof(struct sadb_alg)) / - IPSEC_PFKEYv2_ALIGN; - pfkey_supported->sadb_supported_exttype = exttype; - pfkey_supported->sadb_supported_reserved = 0; - - pfkey_alg = (struct sadb_alg*)((char*)pfkey_supported + sizeof(struct sadb_supported)); - for(i = 0; i < alg_num; i++) { - memcpy (pfkey_alg, &(alg[i]), sizeof(struct sadb_alg)); - pfkey_alg->sadb_alg_reserved = 0; - pfkey_alg++; - } - -#if 0 - DEBUGGING( - "pfkey_supported_build: " - "Sorry, I can't build exttype=%d yet.\n", - (*pfkey_ext)->sadb_ext_type); - SENDERR(EINVAL); /* don't process these yet */ - - uint8_t sadb_alg_id; - uint8_t sadb_alg_ivlen; - uint16_t sadb_alg_minbits; - uint16_t sadb_alg_maxbits; - uint16_t sadb_alg_reserved; -#endif -errlab: - return error; -} - -int -pfkey_spirange_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint32_t min, /* in network order */ - uint32_t max) /* in network order */ -{ - int error = 0; - struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext; - - /* sanity checks... */ - if (pfkey_spirange) { - DEBUGGING( - "pfkey_spirange_build: " - "why is pfkey_spirange already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (ntohl(max) < ntohl(min)) { - DEBUGGING( - "pfkey_spirange_build: " - "minspi=%08x must be < maxspi=%08x.\n", - ntohl(min), - ntohl(max)); - SENDERR(EINVAL); - } - - if (ntohl(min) <= 255) { - DEBUGGING( - "pfkey_spirange_build: " - "minspi=%08x must be > 255.\n", - ntohl(min)); - SENDERR(EEXIST); - } - - pfkey_spirange = (struct sadb_spirange*) - MALLOC(sizeof(struct sadb_spirange)); - *pfkey_ext = (struct sadb_ext*)pfkey_spirange; - - if (pfkey_spirange == NULL) { - DEBUGGING( - "pfkey_spirange_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_spirange, - 0, - sizeof(struct sadb_spirange)); - - pfkey_spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN; - - pfkey_spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE; - pfkey_spirange->sadb_spirange_min = min; - pfkey_spirange->sadb_spirange_max = max; - pfkey_spirange->sadb_spirange_reserved = 0; - errlab: - return error; -} - -int -pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext) -{ - int error = 0; - struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)*pfkey_ext; - - /* sanity checks... */ - if (pfkey_x_kmprivate) { - DEBUGGING( - "pfkey_x_kmprivate_build: " - "why is pfkey_x_kmprivate already pointing to something?\n"); - SENDERR(EINVAL); - } - - pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0; - - DEBUGGING( - "pfkey_x_kmprivate_build: " - "Sorry, I can't build exttype=%d yet.\n", - (*pfkey_ext)->sadb_ext_type); - SENDERR(EINVAL); /* don't process these yet */ - - pfkey_x_kmprivate = (struct sadb_x_kmprivate*) - MALLOC(sizeof(struct sadb_x_kmprivate)); - *pfkey_ext = (struct sadb_ext*)pfkey_x_kmprivate; - - if (pfkey_x_kmprivate == NULL) { - DEBUGGING( - "pfkey_x_kmprivate_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_x_kmprivate, - 0, - sizeof(struct sadb_x_kmprivate)); - - pfkey_x_kmprivate->sadb_x_kmprivate_len = - sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN; - - pfkey_x_kmprivate->sadb_x_kmprivate_exttype = SADB_X_EXT_KMPRIVATE; - pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0; -errlab: - return error; -} - -int -pfkey_x_satype_build(struct sadb_ext** pfkey_ext, - uint8_t satype) -{ - int error = 0; - int i; - struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)*pfkey_ext; - - DEBUGGING( - "pfkey_x_satype_build:\n"); - /* sanity checks... */ - if (pfkey_x_satype) { - DEBUGGING( - "pfkey_x_satype_build: " - "why is pfkey_x_satype already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (!satype) { - DEBUGGING( - "pfkey_x_satype_build: " - "SA type not set, must be non-zero.\n"); - SENDERR(EINVAL); - } - - if (satype > SADB_SATYPE_MAX) { - DEBUGGING( - "pfkey_x_satype_build: " - "satype %d > max %d\n", - satype, SADB_SATYPE_MAX); - SENDERR(EINVAL); - } - - pfkey_x_satype = (struct sadb_x_satype*) - MALLOC(sizeof(struct sadb_x_satype)); - - *pfkey_ext = (struct sadb_ext*)pfkey_x_satype; - - if (pfkey_x_satype == NULL) { - DEBUGGING( - "pfkey_x_satype_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_x_satype, - 0, - sizeof(struct sadb_x_satype)); - - pfkey_x_satype->sadb_x_satype_len = sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN; - - pfkey_x_satype->sadb_x_satype_exttype = SADB_X_EXT_SATYPE2; - pfkey_x_satype->sadb_x_satype_satype = satype; - for (i=0; i<3; i++) { - pfkey_x_satype->sadb_x_satype_reserved[i] = 0; - } - -errlab: - return error; -} - -int -pfkey_x_debug_build(struct sadb_ext** pfkey_ext, - uint32_t tunnel, - uint32_t netlink, - uint32_t xform, - uint32_t eroute, - uint32_t spi, - uint32_t radij, - uint32_t esp, - uint32_t ah, - uint32_t rcv, - uint32_t pfkey, - uint32_t ipcomp, - uint32_t verbose) -{ - int error = 0; - int i; - struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)*pfkey_ext; - - DEBUGGING( - "pfkey_x_debug_build:\n"); - /* sanity checks... */ - if (pfkey_x_debug) { - DEBUGGING( - "pfkey_x_debug_build: " - "why is pfkey_x_debug already pointing to something?\n"); - SENDERR(EINVAL); - } - - DEBUGGING( - "pfkey_x_debug_build: " - "tunnel=%x netlink=%x xform=%x eroute=%x spi=%x radij=%x esp=%x ah=%x rcv=%x pfkey=%x ipcomp=%x verbose=%x?\n", - tunnel, netlink, xform, eroute, spi, radij, esp, ah, rcv, pfkey, ipcomp, verbose); - - pfkey_x_debug = (struct sadb_x_debug*) - MALLOC(sizeof(struct sadb_x_debug)); - *pfkey_ext = (struct sadb_ext*)pfkey_x_debug; - - if (pfkey_x_debug == NULL) { - DEBUGGING( - "pfkey_x_debug_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } -#if 0 - memset(pfkey_x_debug, - 0, - sizeof(struct sadb_x_debug)); -#endif - - pfkey_x_debug->sadb_x_debug_len = sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN; - pfkey_x_debug->sadb_x_debug_exttype = SADB_X_EXT_DEBUG; - - pfkey_x_debug->sadb_x_debug_tunnel = tunnel; - pfkey_x_debug->sadb_x_debug_netlink = netlink; - pfkey_x_debug->sadb_x_debug_xform = xform; - pfkey_x_debug->sadb_x_debug_eroute = eroute; - pfkey_x_debug->sadb_x_debug_spi = spi; - pfkey_x_debug->sadb_x_debug_radij = radij; - pfkey_x_debug->sadb_x_debug_esp = esp; - pfkey_x_debug->sadb_x_debug_ah = ah; - pfkey_x_debug->sadb_x_debug_rcv = rcv; - pfkey_x_debug->sadb_x_debug_pfkey = pfkey; - pfkey_x_debug->sadb_x_debug_ipcomp = ipcomp; - pfkey_x_debug->sadb_x_debug_verbose = verbose; - - for (i=0; i<4; i++) { - pfkey_x_debug->sadb_x_debug_reserved[i] = 0; - } - -errlab: - return error; -} - -int -pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext, - uint8_t type) -{ - int error = 0; - int i; - struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)*pfkey_ext; - - DEBUGGING( - "pfkey_x_nat_t_type_build:\n"); - /* sanity checks... */ - if (pfkey_x_nat_t_type) { - DEBUGGING( - "pfkey_x_nat_t_type_build: " - "why is pfkey_x_nat_t_type already pointing to something?\n"); - SENDERR(EINVAL); - } - - DEBUGGING( - "pfkey_x_nat_t_type_build: " - "type=%d\n", type); - - pfkey_x_nat_t_type = (struct sadb_x_nat_t_type*) - MALLOC(sizeof(struct sadb_x_nat_t_type)); - - *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_type; - if (pfkey_x_nat_t_type == NULL) { - DEBUGGING( - "pfkey_x_nat_t_type_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - - pfkey_x_nat_t_type->sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / IPSEC_PFKEYv2_ALIGN; - pfkey_x_nat_t_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; - pfkey_x_nat_t_type->sadb_x_nat_t_type_type = type; - for (i=0; i<3; i++) { - pfkey_x_nat_t_type->sadb_x_nat_t_type_reserved[i] = 0; - } - -errlab: - return error; -} - -int -pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t port) -{ - int error = 0; - struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)*pfkey_ext; - - DEBUGGING( - "pfkey_x_nat_t_port_build:\n"); - /* sanity checks... */ - if (pfkey_x_nat_t_port) { - DEBUGGING( - "pfkey_x_nat_t_port_build: " - "why is pfkey_x_nat_t_port already pointing to something?\n"); - SENDERR(EINVAL); - } - - switch (exttype) { - case SADB_X_EXT_NAT_T_SPORT: - case SADB_X_EXT_NAT_T_DPORT: - break; - default: - DEBUGGING( - "pfkey_nat_t_port_build: " - "unrecognised ext_type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - DEBUGGING( - "pfkey_x_nat_t_port_build: " - "ext=%d, port=%d\n", exttype, port); - - pfkey_x_nat_t_port = (struct sadb_x_nat_t_port*) - MALLOC(sizeof(struct sadb_x_nat_t_port)); - *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_port; - - if (pfkey_x_nat_t_port == NULL) { - DEBUGGING( - "pfkey_x_nat_t_port_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - - pfkey_x_nat_t_port->sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / IPSEC_PFKEYv2_ALIGN; - pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype = exttype; - pfkey_x_nat_t_port->sadb_x_nat_t_port_port = port; - pfkey_x_nat_t_port->sadb_x_nat_t_port_reserved = 0; - -errlab: - return error; -} - -int pfkey_x_protocol_build(struct sadb_ext **pfkey_ext, - uint8_t protocol) -{ - int error = 0; - struct sadb_protocol * p = (struct sadb_protocol *)*pfkey_ext; - DEBUGGING("pfkey_x_protocol_build: protocol=%u\n", protocol); - /* sanity checks... */ - if (p != 0) { - DEBUGGING("pfkey_x_protocol_build: bogus protocol pointer\n"); - SENDERR(EINVAL); - } - if ((p = (struct sadb_protocol*)MALLOC(sizeof(*p))) == 0) { - DEBUGGING("pfkey_build: memory allocation failed\n"); - SENDERR(ENOMEM); - } - *pfkey_ext = (struct sadb_ext *)p; - p->sadb_protocol_len = sizeof(*p) / sizeof(uint64_t); - p->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; - p->sadb_protocol_proto = protocol; - p->sadb_protocol_flags = 0; - p->sadb_protocol_reserved2 = 0; - errlab: - return error; -} - - -#if I_DONT_THINK_THIS_WILL_BE_USEFUL -int (*ext_default_builders[SADB_EXT_MAX +1])(struct sadb_msg*, struct sadb_ext*) - = -{ - NULL, /* pfkey_msg_build, */ - pfkey_sa_build, - pfkey_lifetime_build, - pfkey_lifetime_build, - pfkey_lifetime_build, - pfkey_address_build, - pfkey_address_build, - pfkey_address_build, - pfkey_key_build, - pfkey_key_build, - pfkey_ident_build, - pfkey_ident_build, - pfkey_sens_build, - pfkey_prop_build, - pfkey_supported_build, - pfkey_supported_build, - pfkey_spirange_build, - pfkey_x_kmprivate_build, - pfkey_x_satype_build, - pfkey_sa_build, - pfkey_address_build, - pfkey_address_build, - pfkey_address_build, - pfkey_address_build, - pfkey_address_build, - pfkey_x_ext_debug_build -}; -#endif - -int -pfkey_msg_build(struct sadb_msg **pfkey_msg, struct sadb_ext *extensions[], int dir) -{ - int error = 0; - unsigned ext; - unsigned total_size; - struct sadb_ext *pfkey_ext; - int extensions_seen = 0; - struct sadb_ext *extensions_check[SADB_EXT_MAX + 1]; - - if (!extensions[0]) { - DEBUGGING( - "pfkey_msg_build: " - "extensions[0] must be specified (struct sadb_msg).\n"); - SENDERR(EINVAL); - } - - total_size = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN; - for (ext = 1; ext <= SADB_EXT_MAX; ext++) { - if(extensions[ext]) { - total_size += (extensions[ext])->sadb_ext_len; - } - } - - if (!(*pfkey_msg = (struct sadb_msg*)MALLOC(total_size * IPSEC_PFKEYv2_ALIGN))) { - DEBUGGING( - "pfkey_msg_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - - DEBUGGING( - "pfkey_msg_build: " - "pfkey_msg=0p%p allocated %lu bytes, &(extensions[0])=0p%p\n", - *pfkey_msg, - (unsigned long)(total_size * IPSEC_PFKEYv2_ALIGN), - &(extensions[0])); - memcpy(*pfkey_msg, - extensions[0], - sizeof(struct sadb_msg)); - (*pfkey_msg)->sadb_msg_len = total_size; - (*pfkey_msg)->sadb_msg_reserved = 0; - extensions_seen = 1 ; - - pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg)); - - for (ext = 1; ext <= SADB_EXT_MAX; ext++) { - /* copy from extension[ext] to buffer */ - if (extensions[ext]) { - /* Is this type of extension permitted for this type of message? */ - if (!(extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type] & - 1<sadb_msg_type], - 1<sadb_ext_len * IPSEC_PFKEYv2_ALIGN), - ext, - extensions[ext], - pfkey_ext); - memcpy(pfkey_ext, - extensions[ext], - (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN); - { - char *pfkey_ext_c = (char *)pfkey_ext; - - pfkey_ext_c += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN; - pfkey_ext = (struct sadb_ext *)pfkey_ext_c; - } - /* Mark that we have seen this extension and remember the header location */ - extensions_seen |= ( 1 << ext ); - } - } - - /* check required extensions */ - DEBUGGING( - "pfkey_msg_build: " - "extensions permitted=%08x, seen=%08x, required=%08x.\n", - extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type], - extensions_seen, - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]); - - if ((extensions_seen & - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) != - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) { - DEBUGGING( - "pfkey_msg_build: " - "required extensions missing:%08x.\n", - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type] - - (extensions_seen & - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) ); - SENDERR(EINVAL); - } - - error = pfkey_msg_parse(*pfkey_msg, NULL, extensions_check, dir); - if (error) { - DEBUGGING( - "pfkey_msg_build: " - "Trouble parsing newly built pfkey message, error=%d.\n", - error); - SENDERR(-error); - } - -errlab: - - return error; -} diff --git a/src/libfreeswan/pfkey_v2_debug.c b/src/libfreeswan/pfkey_v2_debug.c deleted file mode 100644 index 0762d8f2b..000000000 --- a/src/libfreeswan/pfkey_v2_debug.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * @(#) pfkey version 2 debugging messages - * - * Copyright (C) 2001 Richard Guy Briggs - * and Michael Richardson - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -# include -# include - -#include "freeswan.h" -#include "pfkeyv2.h" -#include "pfkey.h" - -/* - * This file provides ASCII translations of PF_KEY magic numbers. - * - */ - -static char *pfkey_sadb_ext_strings[]={ - "reserved", /* SADB_EXT_RESERVED 0 */ - "security-association", /* SADB_EXT_SA 1 */ - "lifetime-current", /* SADB_EXT_LIFETIME_CURRENT 2 */ - "lifetime-hard", /* SADB_EXT_LIFETIME_HARD 3 */ - "lifetime-soft", /* SADB_EXT_LIFETIME_SOFT 4 */ - "source-address", /* SADB_EXT_ADDRESS_SRC 5 */ - "destination-address", /* SADB_EXT_ADDRESS_DST 6 */ - "proxy-address", /* SADB_EXT_ADDRESS_PROXY 7 */ - "authentication-key", /* SADB_EXT_KEY_AUTH 8 */ - "cipher-key", /* SADB_EXT_KEY_ENCRYPT 9 */ - "source-identity", /* SADB_EXT_IDENTITY_SRC 10 */ - "destination-identity", /* SADB_EXT_IDENTITY_DST 11 */ - "sensitivity-label", /* SADB_EXT_SENSITIVITY 12 */ - "proposal", /* SADB_EXT_PROPOSAL 13 */ - "supported-auth", /* SADB_EXT_SUPPORTED_AUTH 14 */ - "supported-cipher", /* SADB_EXT_SUPPORTED_ENCRYPT 15 */ - "spi-range", /* SADB_EXT_SPIRANGE 16 */ - "X-kmpprivate", /* SADB_X_EXT_KMPRIVATE 17 */ - "X-satype2", /* SADB_X_EXT_SATYPE2 18 */ - "X-security-association", /* SADB_X_EXT_SA2 19 */ - "X-destination-address2", /* SADB_X_EXT_ADDRESS_DST2 20 */ - "X-source-flow-address", /* SADB_X_EXT_ADDRESS_SRC_FLOW 21 */ - "X-dest-flow-address", /* SADB_X_EXT_ADDRESS_DST_FLOW 22 */ - "X-source-mask", /* SADB_X_EXT_ADDRESS_SRC_MASK 23 */ - "X-dest-mask", /* SADB_X_EXT_ADDRESS_DST_MASK 24 */ - "X-set-debug", /* SADB_X_EXT_DEBUG 25 */ - "X-protocol", /* SADB_X_EXT_PROTOCOL 26 */ - "X-NAT-T-type", /* SADB_X_EXT_NAT_T_TYPE 27 */ - "X-NAT-T-sport", /* SADB_X_EXT_NAT_T_SPORT 28 */ - "X-NAT-T-dport", /* SADB_X_EXT_NAT_T_DPORT 29 */ - "X-NAT-T-OA", /* SADB_X_EXT_NAT_T_OA 30 */ -}; - -const char * -pfkey_v2_sadb_ext_string(int ext) -{ - if(ext <= SADB_EXT_MAX) { - return pfkey_sadb_ext_strings[ext]; - } else { - return "unknown-ext"; - } -} - - -static char *pfkey_sadb_type_strings[]={ - "reserved", /* SADB_RESERVED */ - "getspi", /* SADB_GETSPI */ - "update", /* SADB_UPDATE */ - "add", /* SADB_ADD */ - "delete", /* SADB_DELETE */ - "get", /* SADB_GET */ - "acquire", /* SADB_ACQUIRE */ - "register", /* SADB_REGISTER */ - "expire", /* SADB_EXPIRE */ - "flush", /* SADB_FLUSH */ - "dump", /* SADB_DUMP */ - "x-promisc", /* SADB_X_PROMISC */ - "x-pchange", /* SADB_X_PCHANGE */ - "x-groupsa", /* SADB_X_GRPSA */ - "x-addflow(eroute)", /* SADB_X_ADDFLOW */ - "x-delflow(eroute)", /* SADB_X_DELFLOW */ - "x-debug", /* SADB_X_DEBUG */ - "x-nat-t-new-mapping", /* SADB_X_NAT_T_NEW_MAPPING */ -}; - -const char * -pfkey_v2_sadb_type_string(int sadb_type) -{ - if(sadb_type <= SADB_MAX) { - return pfkey_sadb_type_strings[sadb_type]; - } else { - return "unknown-sadb-type"; - } -} diff --git a/src/libfreeswan/pfkey_v2_ext_bits.c b/src/libfreeswan/pfkey_v2_ext_bits.c deleted file mode 100644 index 49b4aa567..000000000 --- a/src/libfreeswan/pfkey_v2_ext_bits.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * RFC2367 PF_KEYv2 Key management API message parser - * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Template from klips/net/ipsec/ipsec/ipsec_parse.c. - */ - -char pfkey_v2_ext_bits_c_version[] = ""; - -# include -# include - -#include -#include -#include - -unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/] = { - -/* INBOUND EXTENSIONS */ -{ - -/* PERMITTED IN */ -{ -/* SADB_RESERVED */ -0 -, -/* SADB_GETSPI */ -1<. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Template from klips/net/ipsec/ipsec/ipsec_parser.c. - */ - -char pfkey_v2_parse_c_version[] = ""; - -# include -# include -# include - -# include -# include -# include /* for PRINTF_LIKE */ -# include /* for debugging and DBG_log */ - -# ifdef PLUTO -# define DEBUGGING(level, args...) { DBG_log("pfkey_lib_debug:" args); } -# else -# define DEBUGGING(level, args...) if(pfkey_lib_debug & level) { printf("pfkey_lib_debug:" args); } else { ; } -# endif - -#include -#include - - -#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0) - -static struct { - uint8_t proto; - uint8_t satype; - char* name; -} satype_tbl[] = { - { SA_ESP, SADB_SATYPE_ESP, "ESP" }, - { SA_AH, SADB_SATYPE_AH, "AH" }, - { SA_IPIP, SADB_X_SATYPE_IPIP, "IPIP" }, - { SA_COMP, SADB_X_SATYPE_COMP, "COMP" }, - { SA_INT, SADB_X_SATYPE_INT, "INT" }, - { 0, 0, "UNKNOWN" } -}; - -uint8_t -satype2proto(uint8_t satype) -{ - int i =0; - - while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) { - i++; - } - return satype_tbl[i].proto; -} - -uint8_t -proto2satype(uint8_t proto) -{ - int i = 0; - - while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) { - i++; - } - return satype_tbl[i].satype; -} - -char* -satype2name(uint8_t satype) -{ - int i = 0; - - while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) { - i++; - } - return satype_tbl[i].name; -} - -char* -proto2name(uint8_t proto) -{ - int i = 0; - - while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) { - i++; - } - return satype_tbl[i].name; -} - -/* Default extension parsers taken from the KLIPS code */ - -DEBUG_NO_STATIC int -pfkey_sa_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext; -#if 0 - struct sadb_sa sav2; -#endif - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_sa_parse: entry\n"); - /* sanity checks... */ - if(!pfkey_sa) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "NULL pointer passed in.\n"); - SENDERR(EINVAL); - } - -#if 0 - /* check if this structure is short, and if so, fix it up. - * XXX this is NOT the way to do things. - */ - if(pfkey_sa->sadb_sa_len == sizeof(struct sadb_sa_v1)/IPSEC_PFKEYv2_ALIGN) { - - /* yes, so clear out a temporary structure, and copy first */ - memset(&sav2, 0, sizeof(sav2)); - memcpy(&sav2, pfkey_sa, sizeof(struct sadb_sa_v1)); - sav2.sadb_x_sa_ref=-1; - sav2.sadb_sa_len = sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN; - - pfkey_sa = &sav2; - } -#endif - - - if(pfkey_sa->sadb_sa_len != sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "length wrong pfkey_sa->sadb_sa_len=%d sizeof(struct sadb_sa)=%d.\n", - pfkey_sa->sadb_sa_len, - (int)sizeof(struct sadb_sa)); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_encrypt > SADB_EALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "pfkey_sa->sadb_sa_encrypt=%d > SADB_EALG_MAX=%d.\n", - pfkey_sa->sadb_sa_encrypt, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_auth > SADB_AALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "pfkey_sa->sadb_sa_auth=%d > SADB_AALG_MAX=%d.\n", - pfkey_sa->sadb_sa_auth, - SADB_AALG_MAX); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_state > SADB_SASTATE_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "state=%d exceeds MAX=%d.\n", - pfkey_sa->sadb_sa_state, - SADB_SASTATE_MAX); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_state == SADB_SASTATE_DEAD) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "state=%d is DEAD=%d.\n", - pfkey_sa->sadb_sa_state, - SADB_SASTATE_DEAD); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_replay > 64) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "replay window size: %d -- must be 0 <= size <= 64\n", - pfkey_sa->sadb_sa_replay); - SENDERR(EINVAL); - } - - if(! ((pfkey_sa->sadb_sa_exttype == SADB_EXT_SA) || - (pfkey_sa->sadb_sa_exttype == SADB_X_EXT_SA2))) - { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "unknown exttype=%d, expecting SADB_EXT_SA=%d or SADB_X_EXT_SA2=%d.\n", - pfkey_sa->sadb_sa_exttype, - SADB_EXT_SA, - SADB_X_EXT_SA2); - SENDERR(EINVAL); - } - - if((IPSEC_SAREF_NULL != pfkey_sa->sadb_x_sa_ref) && (pfkey_sa->sadb_x_sa_ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n", - pfkey_sa->sadb_x_sa_ref, - IPSEC_SAREF_NULL, - IPSEC_SA_REF_TABLE_NUM_ENTRIES); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_sa_parse: " - "successfully found len=%d exttype=%d(%s) spi=%08lx replay=%d state=%d auth=%d encrypt=%d flags=%d ref=%d.\n", - pfkey_sa->sadb_sa_len, - pfkey_sa->sadb_sa_exttype, - pfkey_v2_sadb_ext_string(pfkey_sa->sadb_sa_exttype), - (long unsigned int)ntohl(pfkey_sa->sadb_sa_spi), - pfkey_sa->sadb_sa_replay, - pfkey_sa->sadb_sa_state, - pfkey_sa->sadb_sa_auth, - pfkey_sa->sadb_sa_encrypt, - pfkey_sa->sadb_sa_flags, - pfkey_sa->sadb_x_sa_ref); - - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_lifetime_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_lifetime_parse:enter\n"); - /* sanity checks... */ - if(!pfkey_lifetime) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_lifetime_parse: " - "NULL pointer passed in.\n"); - SENDERR(EINVAL); - } - - if(pfkey_lifetime->sadb_lifetime_len != - sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_lifetime_parse: " - "length wrong pfkey_lifetime->sadb_lifetime_len=%d sizeof(struct sadb_lifetime)=%d.\n", - pfkey_lifetime->sadb_lifetime_len, - (int)sizeof(struct sadb_lifetime)); - SENDERR(EINVAL); - } - - if((pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_HARD) && - (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_SOFT) && - (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_CURRENT)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_lifetime_parse: " - "unexpected ext_type=%d.\n", - pfkey_lifetime->sadb_lifetime_exttype); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_lifetime_parse: " - "life_type=%d(%s) alloc=%u bytes=%u add=%u use=%u pkts=%u.\n", - pfkey_lifetime->sadb_lifetime_exttype, - pfkey_v2_sadb_ext_string(pfkey_lifetime->sadb_lifetime_exttype), - pfkey_lifetime->sadb_lifetime_allocations, - (unsigned)pfkey_lifetime->sadb_lifetime_bytes, - (unsigned)pfkey_lifetime->sadb_lifetime_addtime, - (unsigned)pfkey_lifetime->sadb_lifetime_usetime, - pfkey_lifetime->sadb_x_lifetime_packets); -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_address_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - int saddr_len = 0; - struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext; - struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address)); - char ipaddr_txt[ADDRTOT_BUF]; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_address_parse:enter\n"); - /* sanity checks... */ - if(!pfkey_address) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "NULL pointer passed in.\n"); - SENDERR(EINVAL); - } - - if(pfkey_address->sadb_address_len < - (sizeof(struct sadb_address) + sizeof(struct sockaddr))/ - IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "size wrong 1 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n", - pfkey_address->sadb_address_len, - (int)sizeof(struct sadb_address), - (int)sizeof(struct sockaddr)); - SENDERR(EINVAL); - } - - if(pfkey_address->sadb_address_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "res=%d, must be zero.\n", - pfkey_address->sadb_address_reserved); - SENDERR(EINVAL); - } - - switch(pfkey_address->sadb_address_exttype) { - case SADB_EXT_ADDRESS_SRC: - case SADB_EXT_ADDRESS_DST: - case SADB_EXT_ADDRESS_PROXY: - case SADB_X_EXT_ADDRESS_DST2: - case SADB_X_EXT_ADDRESS_SRC_FLOW: - case SADB_X_EXT_ADDRESS_DST_FLOW: - case SADB_X_EXT_ADDRESS_SRC_MASK: - case SADB_X_EXT_ADDRESS_DST_MASK: - case SADB_X_EXT_NAT_T_OA: - break; - default: - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "unexpected ext_type=%d.\n", - pfkey_address->sadb_address_exttype); - SENDERR(EINVAL); - } - - switch(s->sa_family) { - case AF_INET: - saddr_len = sizeof(struct sockaddr_in); - sprintf(ipaddr_txt, "%d.%d.%d.%d" - , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 0) & 0xFF - , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 8) & 0xFF - , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 16) & 0xFF - , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 24) & 0xFF); - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_address_parse: " - "found exttype=%u(%s) family=%d(AF_INET) address=%s proto=%u port=%u.\n", - pfkey_address->sadb_address_exttype, - pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype), - s->sa_family, - ipaddr_txt, - pfkey_address->sadb_address_proto, - ntohs(((struct sockaddr_in*)s)->sin_port)); - break; - case AF_INET6: - saddr_len = sizeof(struct sockaddr_in6); - sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x" - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[0]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[1]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[2]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[3]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[4]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[5]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[6]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[7])); - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_address_parse: " - "found exttype=%u(%s) family=%d(AF_INET6) address=%s proto=%u port=%u.\n", - pfkey_address->sadb_address_exttype, - pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype), - s->sa_family, - ipaddr_txt, - pfkey_address->sadb_address_proto, - ((struct sockaddr_in6*)s)->sin6_port); - break; - default: - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "s->sa_family=%d not supported.\n", - s->sa_family); - SENDERR(EPFNOSUPPORT); - } - - if(pfkey_address->sadb_address_len != - DIVUP(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "size wrong 2 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n", - pfkey_address->sadb_address_len, - (int)sizeof(struct sadb_address), - saddr_len); - SENDERR(EINVAL); - } - - if(pfkey_address->sadb_address_prefixlen != 0) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "address prefixes not supported yet.\n"); - SENDERR(EAFNOSUPPORT); /* not supported yet */ - } - - /* XXX check if port!=0 */ - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_address_parse: successful.\n"); - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_key_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_key_parse:enter\n"); - /* sanity checks... */ - - if(!pfkey_key) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "NULL pointer passed in.\n"); - SENDERR(EINVAL); - } - - if(pfkey_key->sadb_key_len < sizeof(struct sadb_key) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_key->sadb_key_len, - (int)sizeof(struct sadb_key)); - SENDERR(EINVAL); - } - - if(!pfkey_key->sadb_key_bits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "key length set to zero, must be non-zero.\n"); - SENDERR(EINVAL); - } - - if(pfkey_key->sadb_key_len != - DIVUP(sizeof(struct sadb_key) * OCTETBITS + pfkey_key->sadb_key_bits, - PFKEYBITS)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "key length=%d does not agree with extension length=%d.\n", - pfkey_key->sadb_key_bits, - pfkey_key->sadb_key_len); - SENDERR(EINVAL); - } - - if(pfkey_key->sadb_key_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "res=%d, must be zero.\n", - pfkey_key->sadb_key_reserved); - SENDERR(EINVAL); - } - - if(! ( (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_AUTH) || - (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_ENCRYPT))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "expecting extension type AUTH or ENCRYPT, got %d.\n", - pfkey_key->sadb_key_exttype); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_key_parse: " - "success, found len=%d exttype=%d(%s) bits=%d reserved=%d.\n", - pfkey_key->sadb_key_len, - pfkey_key->sadb_key_exttype, - pfkey_v2_sadb_ext_string(pfkey_key->sadb_key_exttype), - pfkey_key->sadb_key_bits, - pfkey_key->sadb_key_reserved); - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_ident_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext; - - /* sanity checks... */ - if(pfkey_ident->sadb_ident_len < sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_ident_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_ident->sadb_ident_len, - (int)sizeof(struct sadb_ident)); - SENDERR(EINVAL); - } - - if(pfkey_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_ident_parse: " - "ident_type=%d out of range, must be less than %d.\n", - pfkey_ident->sadb_ident_type, - SADB_IDENTTYPE_MAX); - SENDERR(EINVAL); - } - - if(pfkey_ident->sadb_ident_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_ident_parse: " - "res=%d, must be zero.\n", - pfkey_ident->sadb_ident_reserved); - SENDERR(EINVAL); - } - - /* string terminator/padding must be zero */ - if(pfkey_ident->sadb_ident_len > sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) { - if(*((char*)pfkey_ident + pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_ident_parse: " - "string padding must be zero, last is 0x%02x.\n", - *((char*)pfkey_ident + - pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)); - SENDERR(EINVAL); - } - } - - if( ! ((pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) || - (pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_DST))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "expecting extension type IDENTITY_SRC or IDENTITY_DST, got %d.\n", - pfkey_ident->sadb_ident_exttype); - SENDERR(EINVAL); - } - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_sens_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_sens *pfkey_sens = (struct sadb_sens *)pfkey_ext; - - /* sanity checks... */ - if(pfkey_sens->sadb_sens_len < sizeof(struct sadb_sens) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sens_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_sens->sadb_sens_len, - (int)sizeof(struct sadb_sens)); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sens_parse: " - "Sorry, I can't parse exttype=%d yet.\n", - pfkey_ext->sadb_ext_type); -#if 0 - SENDERR(EINVAL); /* don't process these yet */ -#endif - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_prop_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - int i, num_comb; - struct sadb_prop *pfkey_prop = (struct sadb_prop *)pfkey_ext; - struct sadb_comb *pfkey_comb = (struct sadb_comb *)((char*)pfkey_ext + sizeof(struct sadb_prop)); - - /* sanity checks... */ - if((pfkey_prop->sadb_prop_len < sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN) || - (((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "size wrong ext_len=%d, prop_ext_len=%d comb_ext_len=%d.\n", - pfkey_prop->sadb_prop_len, - (int)sizeof(struct sadb_prop), - (int)sizeof(struct sadb_comb)); - SENDERR(EINVAL); - } - - if(pfkey_prop->sadb_prop_replay > 64) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "replay window size: %d -- must be 0 <= size <= 64\n", - pfkey_prop->sadb_prop_replay); - SENDERR(EINVAL); - } - - for(i=0; i<3; i++) { - if(pfkey_prop->sadb_prop_reserved[i]) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "res[%d]=%d, must be zero.\n", - i, pfkey_prop->sadb_prop_reserved[i]); - SENDERR(EINVAL); - } - } - - num_comb = ((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) / sizeof(struct sadb_comb); - - for(i = 0; i < num_comb; i++) { - if(pfkey_comb->sadb_comb_auth > SADB_AALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth=%d > SADB_AALG_MAX=%d.\n", - i, - pfkey_comb->sadb_comb_auth, - SADB_AALG_MAX); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_auth) { - if(!pfkey_comb->sadb_comb_auth_minbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_minbits=0, fatal.\n", - i); - SENDERR(EINVAL); - } - if(!pfkey_comb->sadb_comb_auth_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_maxbits=0, fatal.\n", - i); - SENDERR(EINVAL); - } - if(pfkey_comb->sadb_comb_auth_minbits > pfkey_comb->sadb_comb_auth_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_minbits=%d > maxbits=%d, fatal.\n", - i, - pfkey_comb->sadb_comb_auth_minbits, - pfkey_comb->sadb_comb_auth_maxbits); - SENDERR(EINVAL); - } - } else { - if(pfkey_comb->sadb_comb_auth_minbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_minbits=%d != 0, fatal.\n", - i, - pfkey_comb->sadb_comb_auth_minbits); - SENDERR(EINVAL); - } - if(pfkey_comb->sadb_comb_auth_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_maxbits=%d != 0, fatal.\n", - i, - pfkey_comb->sadb_comb_auth_maxbits); - SENDERR(EINVAL); - } - } - - if(pfkey_comb->sadb_comb_encrypt > SADB_EALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_comb_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt=%d > SADB_EALG_MAX=%d.\n", - i, - pfkey_comb->sadb_comb_encrypt, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_encrypt) { - if(!pfkey_comb->sadb_comb_encrypt_minbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_minbits=0, fatal.\n", - i); - SENDERR(EINVAL); - } - if(!pfkey_comb->sadb_comb_encrypt_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=0, fatal.\n", - i); - SENDERR(EINVAL); - } - if(pfkey_comb->sadb_comb_encrypt_minbits > pfkey_comb->sadb_comb_encrypt_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d > maxbits=%d, fatal.\n", - i, - pfkey_comb->sadb_comb_encrypt_minbits, - pfkey_comb->sadb_comb_encrypt_maxbits); - SENDERR(EINVAL); - } - } else { - if(pfkey_comb->sadb_comb_encrypt_minbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d != 0, fatal.\n", - i, - pfkey_comb->sadb_comb_encrypt_minbits); - SENDERR(EINVAL); - } - if(pfkey_comb->sadb_comb_encrypt_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=%d != 0, fatal.\n", - i, - pfkey_comb->sadb_comb_encrypt_maxbits); - SENDERR(EINVAL); - } - } - - /* XXX do sanity check on flags */ - - if(pfkey_comb->sadb_comb_hard_allocations && pfkey_comb->sadb_comb_soft_allocations > pfkey_comb->sadb_comb_hard_allocations) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_soft_allocations=%d > hard_allocations=%d, fatal.\n", - i, - pfkey_comb->sadb_comb_soft_allocations, - pfkey_comb->sadb_comb_hard_allocations); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_hard_bytes && pfkey_comb->sadb_comb_soft_bytes > pfkey_comb->sadb_comb_hard_bytes) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_soft_bytes=%Ld > hard_bytes=%Ld, fatal.\n", - i, - (unsigned long long int)pfkey_comb->sadb_comb_soft_bytes, - (unsigned long long int)pfkey_comb->sadb_comb_hard_bytes); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_hard_addtime && pfkey_comb->sadb_comb_soft_addtime > pfkey_comb->sadb_comb_hard_addtime) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_soft_addtime=%Ld > hard_addtime=%Ld, fatal.\n", - i, - (unsigned long long int)pfkey_comb->sadb_comb_soft_addtime, - (unsigned long long int)pfkey_comb->sadb_comb_hard_addtime); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_hard_usetime && pfkey_comb->sadb_comb_soft_usetime > pfkey_comb->sadb_comb_hard_usetime) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_soft_usetime=%Ld > hard_usetime=%Ld, fatal.\n", - i, - (unsigned long long int)pfkey_comb->sadb_comb_soft_usetime, - (unsigned long long int)pfkey_comb->sadb_comb_hard_usetime); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_x_comb_hard_packets && pfkey_comb->sadb_x_comb_soft_packets > pfkey_comb->sadb_x_comb_hard_packets) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_x_comb_soft_packets=%d > hard_packets=%d, fatal.\n", - i, - pfkey_comb->sadb_x_comb_soft_packets, - pfkey_comb->sadb_x_comb_hard_packets); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "comb[%d].res=%d, must be zero.\n", - i, - pfkey_comb->sadb_comb_reserved); - SENDERR(EINVAL); - } - pfkey_comb++; - } - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_supported_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - unsigned int i, num_alg; - struct sadb_supported *pfkey_supported = (struct sadb_supported *)pfkey_ext; - struct sadb_alg *pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported)); - - /* sanity checks... */ - if((pfkey_supported->sadb_supported_len < - sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN) || - (((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - - sizeof(struct sadb_supported)) % sizeof(struct sadb_alg))) { - - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "size wrong ext_len=%d, supported_ext_len=%d alg_ext_len=%d.\n", - pfkey_supported->sadb_supported_len, - (int)sizeof(struct sadb_supported), - (int)sizeof(struct sadb_alg)); - SENDERR(EINVAL); - } - - if(pfkey_supported->sadb_supported_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "res=%d, must be zero.\n", - pfkey_supported->sadb_supported_reserved); - SENDERR(EINVAL); - } - - num_alg = ((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg); - - for(i = 0; i < num_alg; i++) { - /* process algo description */ - if(pfkey_alg->sadb_alg_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "alg[%d], id=%d, ivlen=%d, minbits=%d, maxbits=%d, res=%d, must be zero.\n", - i, - pfkey_alg->sadb_alg_id, - pfkey_alg->sadb_alg_ivlen, - pfkey_alg->sadb_alg_minbits, - pfkey_alg->sadb_alg_maxbits, - pfkey_alg->sadb_alg_reserved); - SENDERR(EINVAL); - } - - /* XXX can alg_id auth/enc be determined from info given? - Yes, but OpenBSD's method does not iteroperate with rfc2367. - rgb, 2000-04-06 */ - - switch(pfkey_supported->sadb_supported_exttype) { - case SADB_EXT_SUPPORTED_AUTH: - if(pfkey_alg->sadb_alg_id > SADB_AALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "alg[%d], alg_id=%d > SADB_AALG_MAX=%d, fatal.\n", - i, - pfkey_alg->sadb_alg_id, - SADB_AALG_MAX); - SENDERR(EINVAL); - } - break; - case SADB_EXT_SUPPORTED_ENCRYPT: - if(pfkey_alg->sadb_alg_id > SADB_EALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n", - i, - pfkey_alg->sadb_alg_id, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - break; - default: - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n", - i, - pfkey_alg->sadb_alg_id, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - pfkey_alg++; - } - - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_spirange_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)pfkey_ext; - - /* sanity checks... */ - if(pfkey_spirange->sadb_spirange_len != - sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_spirange_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_spirange->sadb_spirange_len, - (int)sizeof(struct sadb_spirange)); - SENDERR(EINVAL); - } - - if(pfkey_spirange->sadb_spirange_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_spirange_parse: " - "reserved=%d must be set to zero.\n", - pfkey_spirange->sadb_spirange_reserved); - SENDERR(EINVAL); - } - - if(ntohl(pfkey_spirange->sadb_spirange_max) < ntohl(pfkey_spirange->sadb_spirange_min)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_spirange_parse: " - "minspi=%08x must be < maxspi=%08x.\n", - ntohl(pfkey_spirange->sadb_spirange_min), - ntohl(pfkey_spirange->sadb_spirange_max)); - SENDERR(EINVAL); - } - - if(ntohl(pfkey_spirange->sadb_spirange_min) <= 255) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_spirange_parse: " - "minspi=%08x must be > 255.\n", - ntohl(pfkey_spirange->sadb_spirange_min)); - SENDERR(EEXIST); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_spirange_parse: " - "ext_len=%u ext_type=%u(%s) min=%u max=%u res=%u.\n", - pfkey_spirange->sadb_spirange_len, - pfkey_spirange->sadb_spirange_exttype, - pfkey_v2_sadb_ext_string(pfkey_spirange->sadb_spirange_exttype), - pfkey_spirange->sadb_spirange_min, - pfkey_spirange->sadb_spirange_max, - pfkey_spirange->sadb_spirange_reserved); - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_kmprivate_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)pfkey_ext; - - /* sanity checks... */ - if(pfkey_x_kmprivate->sadb_x_kmprivate_len < - sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_kmprivate_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_x_kmprivate->sadb_x_kmprivate_len, - (int)sizeof(struct sadb_x_kmprivate)); - SENDERR(EINVAL); - } - - if(pfkey_x_kmprivate->sadb_x_kmprivate_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_kmprivate_parse: " - "reserved=%d must be set to zero.\n", - pfkey_x_kmprivate->sadb_x_kmprivate_reserved); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_kmprivate_parse: " - "Sorry, I can't parse exttype=%d yet.\n", - pfkey_ext->sadb_ext_type); - SENDERR(EINVAL); /* don't process these yet */ - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_satype_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - int i; - struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_x_satype_parse: enter\n"); - /* sanity checks... */ - if(pfkey_x_satype->sadb_x_satype_len != - sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_x_satype->sadb_x_satype_len, - (int)sizeof(struct sadb_x_satype)); - SENDERR(EINVAL); - } - - if(!pfkey_x_satype->sadb_x_satype_satype) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "satype is zero, must be non-zero.\n"); - SENDERR(EINVAL); - } - - if(pfkey_x_satype->sadb_x_satype_satype > SADB_SATYPE_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "satype %d > max %d, invalid.\n", - pfkey_x_satype->sadb_x_satype_satype, SADB_SATYPE_MAX); - SENDERR(EINVAL); - } - - if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "proto lookup from satype=%d failed.\n", - pfkey_x_satype->sadb_x_satype_satype); - SENDERR(EINVAL); - } - - for(i = 0; i < 3; i++) { - if(pfkey_x_satype->sadb_x_satype_reserved[i]) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "reserved[%d]=%d must be set to zero.\n", - i, pfkey_x_satype->sadb_x_satype_reserved[i]); - SENDERR(EINVAL); - } - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_x_satype_parse: " - "len=%u ext=%u(%s) satype=%u(%s) res=%u,%u,%u.\n", - pfkey_x_satype->sadb_x_satype_len, - pfkey_x_satype->sadb_x_satype_exttype, - pfkey_v2_sadb_ext_string(pfkey_x_satype->sadb_x_satype_exttype), - pfkey_x_satype->sadb_x_satype_satype, - satype2name(pfkey_x_satype->sadb_x_satype_satype), - pfkey_x_satype->sadb_x_satype_reserved[0], - pfkey_x_satype->sadb_x_satype_reserved[1], - pfkey_x_satype->sadb_x_satype_reserved[2]); -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_ext_debug_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - int i; - struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_x_debug_parse: enter\n"); - /* sanity checks... */ - if(pfkey_x_debug->sadb_x_debug_len != - sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_debug_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_x_debug->sadb_x_debug_len, - (int)sizeof(struct sadb_x_debug)); - SENDERR(EINVAL); - } - - for(i = 0; i < 4; i++) { - if(pfkey_x_debug->sadb_x_debug_reserved[i]) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_debug_parse: " - "reserved[%d]=%d must be set to zero.\n", - i, pfkey_x_debug->sadb_x_debug_reserved[i]); - SENDERR(EINVAL); - } - } - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_ext_protocol_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_protocol *p = (struct sadb_protocol *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_protocol_parse:\n"); - /* sanity checks... */ - - if (p->sadb_protocol_len != sizeof(*p)/IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_protocol_parse: size wrong ext_len=%d, key_ext_len=%d.\n", - p->sadb_protocol_len, (int)sizeof(*p)); - SENDERR(EINVAL); - } - - if (p->sadb_protocol_reserved2 != 0) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_protocol_parse: res=%d, must be zero.\n", - p->sadb_protocol_reserved2); - SENDERR(EINVAL); - } - - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_ext_nat_t_type_parse(struct sadb_ext *pfkey_ext) -{ - return 0; -} - -DEBUG_NO_STATIC int -pfkey_x_ext_nat_t_port_parse(struct sadb_ext *pfkey_ext) -{ - return 0; -} - -#define DEFINEPARSER(NAME) static struct pf_key_ext_parsers_def NAME##_def={NAME, #NAME}; - -DEFINEPARSER(pfkey_sa_parse); -DEFINEPARSER(pfkey_lifetime_parse); -DEFINEPARSER(pfkey_address_parse); -DEFINEPARSER(pfkey_key_parse); -DEFINEPARSER(pfkey_ident_parse); -DEFINEPARSER(pfkey_sens_parse); -DEFINEPARSER(pfkey_prop_parse); -DEFINEPARSER(pfkey_supported_parse); -DEFINEPARSER(pfkey_spirange_parse); -DEFINEPARSER(pfkey_x_kmprivate_parse); -DEFINEPARSER(pfkey_x_satype_parse); -DEFINEPARSER(pfkey_x_ext_debug_parse); -DEFINEPARSER(pfkey_x_ext_protocol_parse); -DEFINEPARSER(pfkey_x_ext_nat_t_type_parse); -DEFINEPARSER(pfkey_x_ext_nat_t_port_parse); - -struct pf_key_ext_parsers_def *ext_default_parsers[]= -{ - NULL, /* pfkey_msg_parse, */ - &pfkey_sa_parse_def, - &pfkey_lifetime_parse_def, - &pfkey_lifetime_parse_def, - &pfkey_lifetime_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_key_parse_def, - &pfkey_key_parse_def, - &pfkey_ident_parse_def, - &pfkey_ident_parse_def, - &pfkey_sens_parse_def, - &pfkey_prop_parse_def, - &pfkey_supported_parse_def, - &pfkey_supported_parse_def, - &pfkey_spirange_parse_def, - &pfkey_x_kmprivate_parse_def, - &pfkey_x_satype_parse_def, - &pfkey_sa_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_x_ext_debug_parse_def, - &pfkey_x_ext_protocol_parse_def , - &pfkey_x_ext_nat_t_type_parse_def, - &pfkey_x_ext_nat_t_port_parse_def, - &pfkey_x_ext_nat_t_port_parse_def, - &pfkey_address_parse_def -}; - -int -pfkey_msg_parse(struct sadb_msg *pfkey_msg, - struct pf_key_ext_parsers_def *ext_parsers[], - struct sadb_ext *extensions[], - int dir) -{ - int error = 0; - int remain; - struct sadb_ext *pfkey_ext; - int extensions_seen = 0; - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_msg_parse: " - "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n", - pfkey_msg->sadb_msg_version, - pfkey_msg->sadb_msg_type, - pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type), - pfkey_msg->sadb_msg_errno, - pfkey_msg->sadb_msg_satype, - satype2name(pfkey_msg->sadb_msg_satype), - pfkey_msg->sadb_msg_len, - pfkey_msg->sadb_msg_reserved, - pfkey_msg->sadb_msg_seq, - pfkey_msg->sadb_msg_pid); - - if(ext_parsers == NULL) ext_parsers = ext_default_parsers; - - pfkey_extensions_init(extensions); - - remain = pfkey_msg->sadb_msg_len; - remain -= sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN; - - pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg + - sizeof(struct sadb_msg)); - - extensions[0] = (struct sadb_ext *) pfkey_msg; - - - if(pfkey_msg->sadb_msg_version != PF_KEY_V2) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "not PF_KEY_V2 msg, found %d, should be %d.\n", - pfkey_msg->sadb_msg_version, - PF_KEY_V2); - SENDERR(EINVAL); - } - - if(!pfkey_msg->sadb_msg_type) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "msg type not set, must be non-zero..\n"); - SENDERR(EINVAL); - } - - if(pfkey_msg->sadb_msg_type > SADB_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "msg type=%d > max=%d.\n", - pfkey_msg->sadb_msg_type, - SADB_MAX); - SENDERR(EINVAL); - } - - switch(pfkey_msg->sadb_msg_type) { - case SADB_GETSPI: - case SADB_UPDATE: - case SADB_ADD: - case SADB_DELETE: - case SADB_GET: - case SADB_X_GRPSA: - case SADB_X_ADDFLOW: - if(!satype2proto(pfkey_msg->sadb_msg_satype)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "satype %d conversion to proto failed for msg_type %d (%s).\n", - pfkey_msg->sadb_msg_satype, - pfkey_msg->sadb_msg_type, - pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); - SENDERR(EINVAL); - } else { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n", - pfkey_msg->sadb_msg_satype, - satype2name(pfkey_msg->sadb_msg_satype), - satype2proto(pfkey_msg->sadb_msg_satype), - pfkey_msg->sadb_msg_type, - pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); - } - /* fall through */ - case SADB_ACQUIRE: - case SADB_REGISTER: - case SADB_EXPIRE: - if(!pfkey_msg->sadb_msg_satype) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "satype is zero, must be non-zero for msg_type %d(%s).\n", - pfkey_msg->sadb_msg_type, - pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); - SENDERR(EINVAL); - } - default: - break; - } - - /* errno must not be set in downward messages */ - /* this is not entirely true... a response to an ACQUIRE could return an error */ - if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "errno set to %d.\n", - pfkey_msg->sadb_msg_errno); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_msg_parse: " - "remain=%d, ext_type=%d(%s), ext_len=%d.\n", - remain, - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - pfkey_ext->sadb_ext_len); - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_msg_parse: " - "extensions permitted=%08x, required=%08x.\n", - extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]); - - extensions_seen = 1; - - while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) { - /* Is there enough message left to support another extension header? */ - if(remain < pfkey_ext->sadb_ext_len) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "remain %d less than ext len %d.\n", - remain, pfkey_ext->sadb_ext_len); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_msg_parse: " - "parsing ext type=%d(%s) remain=%d.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - remain); - - /* Is the extension header type valid? */ - if((pfkey_ext->sadb_ext_type > SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ext type %d(%s) invalid, SADB_EXT_MAX=%d.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - SADB_EXT_MAX); - SENDERR(EINVAL); - } - - /* Have we already seen this type of extension? */ - if((extensions_seen & ( 1 << pfkey_ext->sadb_ext_type )) != 0) - { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ext type %d(%s) already seen.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type)); - SENDERR(EINVAL); - } - - /* Do I even know about this type of extension? */ - if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ext type %d(%s) unknown, ignoring.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type)); - goto next_ext; - } - - /* Is this type of extension permitted for this type of message? */ - if(!(extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type] & - 1<sadb_ext_type)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ext type %d(%s) not permitted, exts_perm_in=%08x, 1<sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], - 1<sadb_ext_type); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_msg_parse: " - "remain=%d ext_type=%d(%s) ext_len=%d parsing ext 0p%p with parser %s.\n", - remain, - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - pfkey_ext->sadb_ext_len, - pfkey_ext, - ext_parsers[pfkey_ext->sadb_ext_type]->parser_name); - - /* Parse the extension */ - if((error = - (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "extension parsing for type %d(%s) failed with error %d.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - error); - SENDERR(-error); - } - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_msg_parse: " - "Extension %d(%s) parsed.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type)); - - /* Mark that we have seen this extension and remember the header location */ - extensions_seen |= ( 1 << pfkey_ext->sadb_ext_type ); - extensions[pfkey_ext->sadb_ext_type] = pfkey_ext; - - next_ext: - /* Calculate how much message remains */ - remain -= pfkey_ext->sadb_ext_len; - - if(!remain) { - break; - } - /* Find the next extension header */ - pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext + - pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN); - } - - if(remain) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "unexpected remainder of %d.\n", - remain); - /* why is there still something remaining? */ - SENDERR(EINVAL); - } - - /* check required extensions */ - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_msg_parse: " - "extensions permitted=%08x, seen=%08x, required=%08x.\n", - extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], - extensions_seen, - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]); - - /* don't check further if it is an error return message since it - may not have a body */ - if(pfkey_msg->sadb_msg_errno) { - SENDERR(-error); - } - - if((extensions_seen & - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) != - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "required extensions missing:%08x.\n", - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type] - - (extensions_seen & - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type])); - SENDERR(EINVAL); - } - - if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == SADB_X_DELFLOW) - && ((extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW) - != SADB_X_EXT_ADDRESS_DELFLOW) - && (((extensions_seen & (1<sadb_sa_flags - & SADB_X_SAFLAGS_CLEARFLOW) - != SADB_X_SAFLAGS_CLEARFLOW))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "required SADB_X_DELFLOW extensions missing: either %08x must be present or %08x must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n", - SADB_X_EXT_ADDRESS_DELFLOW - - (extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW), - (1<sadb_msg_type) { - case SADB_ADD: - case SADB_UPDATE: - /* check maturity */ - if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != - SADB_SASTATE_MATURE) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "state=%d for add or update should be MATURE=%d.\n", - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state, - SADB_SASTATE_MATURE); - SENDERR(EINVAL); - } - - /* check AH and ESP */ - switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) { - case SADB_SATYPE_AH: - if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth != - SADB_AALG_NONE)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "auth alg is zero, must be non-zero for AH SAs.\n"); - SENDERR(EINVAL); - } - if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt != - SADB_EALG_NONE) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "AH handed encalg=%d, must be zero.\n", - ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt); - SENDERR(EINVAL); - } - break; - case SADB_SATYPE_ESP: - if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt != - SADB_EALG_NONE)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n", - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt, - ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype); - SENDERR(EINVAL); - } - if((((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt == - SADB_EALG_NULL) && - (((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth == - SADB_AALG_NONE) ) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ESP handed encNULL+authNONE, illegal combination.\n"); - SENDERR(EINVAL); - } - break; - case SADB_X_SATYPE_COMP: - if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt != - SADB_EALG_NONE)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n", - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt, - ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype); - SENDERR(EINVAL); - } - if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth != - SADB_AALG_NONE) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "COMP handed auth=%d, must be zero.\n", - ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth); - SENDERR(EINVAL); - } - break; - default: - break; - } - if(ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "spi=%08x must be > 255.\n", - ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi)); - SENDERR(EINVAL); - } - default: - break; - } -errlab: - - return error; -} diff --git a/src/libfreeswan/pfkeyv2.h b/src/libfreeswan/pfkeyv2.h deleted file mode 100644 index 725997ebc..000000000 --- a/src/libfreeswan/pfkeyv2.h +++ /dev/null @@ -1,368 +0,0 @@ -/* -RFC 2367 PF_KEY Key Management API July 1998 - - -Appendix D: Sample Header File - -This file defines structures and symbols for the PF_KEY Version 2 -key management interface. It was written at the U.S. Naval Research -Laboratory. This file is in the public domain. The authors ask that -you leave this credit intact on any copies of this file. -*/ -#ifndef __PFKEY_V2_H -#define __PFKEY_V2_H 1 - -#define PF_KEY_V2 2 -#define PFKEYV2_REVISION 199806L - -#define SADB_RESERVED 0 -#define SADB_GETSPI 1 -#define SADB_UPDATE 2 -#define SADB_ADD 3 -#define SADB_DELETE 4 -#define SADB_GET 5 -#define SADB_ACQUIRE 6 -#define SADB_REGISTER 7 -#define SADB_EXPIRE 8 -#define SADB_FLUSH 9 -#define SADB_DUMP 10 -#define SADB_X_PROMISC 11 -#define SADB_X_PCHANGE 12 -#define SADB_X_GRPSA 13 -#define SADB_X_ADDFLOW 14 -#define SADB_X_DELFLOW 15 -#define SADB_X_DEBUG 16 -#define SADB_X_NAT_T_NEW_MAPPING 17 -#define SADB_MAX 17 - -struct sadb_msg { - uint8_t sadb_msg_version; - uint8_t sadb_msg_type; - uint8_t sadb_msg_errno; - uint8_t sadb_msg_satype; - uint16_t sadb_msg_len; - uint16_t sadb_msg_reserved; - uint32_t sadb_msg_seq; - uint32_t sadb_msg_pid; -}; - -struct sadb_ext { - uint16_t sadb_ext_len; - uint16_t sadb_ext_type; -}; - -struct sadb_sa { - uint16_t sadb_sa_len; - uint16_t sadb_sa_exttype; - uint32_t sadb_sa_spi; - uint8_t sadb_sa_replay; - uint8_t sadb_sa_state; - uint8_t sadb_sa_auth; - uint8_t sadb_sa_encrypt; - uint32_t sadb_sa_flags; - uint32_t /*IPsecSAref_t*/ sadb_x_sa_ref; /* 32 bits */ - uint8_t sadb_x_reserved[4]; -}; - -struct sadb_sa_v1 { - uint16_t sadb_sa_len; - uint16_t sadb_sa_exttype; - uint32_t sadb_sa_spi; - uint8_t sadb_sa_replay; - uint8_t sadb_sa_state; - uint8_t sadb_sa_auth; - uint8_t sadb_sa_encrypt; - uint32_t sadb_sa_flags; -}; - -struct sadb_lifetime { - uint16_t sadb_lifetime_len; - uint16_t sadb_lifetime_exttype; - uint32_t sadb_lifetime_allocations; - uint64_t sadb_lifetime_bytes; - uint64_t sadb_lifetime_addtime; - uint64_t sadb_lifetime_usetime; - uint32_t sadb_x_lifetime_packets; - uint32_t sadb_x_lifetime_reserved; -}; - -struct sadb_address { - uint16_t sadb_address_len; - uint16_t sadb_address_exttype; - uint8_t sadb_address_proto; - uint8_t sadb_address_prefixlen; - uint16_t sadb_address_reserved; -}; - -struct sadb_key { - uint16_t sadb_key_len; - uint16_t sadb_key_exttype; - uint16_t sadb_key_bits; - uint16_t sadb_key_reserved; -}; - -struct sadb_ident { - uint16_t sadb_ident_len; - uint16_t sadb_ident_exttype; - uint16_t sadb_ident_type; - uint16_t sadb_ident_reserved; - uint64_t sadb_ident_id; -}; - -struct sadb_sens { - uint16_t sadb_sens_len; - uint16_t sadb_sens_exttype; - uint32_t sadb_sens_dpd; - uint8_t sadb_sens_sens_level; - uint8_t sadb_sens_sens_len; - uint8_t sadb_sens_integ_level; - uint8_t sadb_sens_integ_len; - uint32_t sadb_sens_reserved; -}; - -struct sadb_prop { - uint16_t sadb_prop_len; - uint16_t sadb_prop_exttype; - uint8_t sadb_prop_replay; - uint8_t sadb_prop_reserved[3]; -}; - -struct sadb_comb { - uint8_t sadb_comb_auth; - uint8_t sadb_comb_encrypt; - uint16_t sadb_comb_flags; - uint16_t sadb_comb_auth_minbits; - uint16_t sadb_comb_auth_maxbits; - uint16_t sadb_comb_encrypt_minbits; - uint16_t sadb_comb_encrypt_maxbits; - uint32_t sadb_comb_reserved; - uint32_t sadb_comb_soft_allocations; - uint32_t sadb_comb_hard_allocations; - uint64_t sadb_comb_soft_bytes; - uint64_t sadb_comb_hard_bytes; - uint64_t sadb_comb_soft_addtime; - uint64_t sadb_comb_hard_addtime; - uint64_t sadb_comb_soft_usetime; - uint64_t sadb_comb_hard_usetime; - uint32_t sadb_x_comb_soft_packets; - uint32_t sadb_x_comb_hard_packets; -}; - -struct sadb_supported { - uint16_t sadb_supported_len; - uint16_t sadb_supported_exttype; - uint32_t sadb_supported_reserved; -}; - -struct sadb_alg { - uint8_t sadb_alg_id; - uint8_t sadb_alg_ivlen; - uint16_t sadb_alg_minbits; - uint16_t sadb_alg_maxbits; - uint16_t sadb_alg_reserved; -}; - -struct sadb_spirange { - uint16_t sadb_spirange_len; - uint16_t sadb_spirange_exttype; - uint32_t sadb_spirange_min; - uint32_t sadb_spirange_max; - uint32_t sadb_spirange_reserved; -}; - -struct sadb_x_kmprivate { - uint16_t sadb_x_kmprivate_len; - uint16_t sadb_x_kmprivate_exttype; - uint32_t sadb_x_kmprivate_reserved; -}; - -struct sadb_x_satype { - uint16_t sadb_x_satype_len; - uint16_t sadb_x_satype_exttype; - uint8_t sadb_x_satype_satype; - uint8_t sadb_x_satype_reserved[3]; -}; - -struct sadb_x_policy { - uint16_t sadb_x_policy_len; - uint16_t sadb_x_policy_exttype; - uint16_t sadb_x_policy_type; - uint8_t sadb_x_policy_dir; - uint8_t sadb_x_policy_reserved; - uint32_t sadb_x_policy_id; - uint32_t sadb_x_policy_reserved2; -}; - -struct sadb_x_debug { - uint16_t sadb_x_debug_len; - uint16_t sadb_x_debug_exttype; - uint32_t sadb_x_debug_tunnel; - uint32_t sadb_x_debug_netlink; - uint32_t sadb_x_debug_xform; - uint32_t sadb_x_debug_eroute; - uint32_t sadb_x_debug_spi; - uint32_t sadb_x_debug_radij; - uint32_t sadb_x_debug_esp; - uint32_t sadb_x_debug_ah; - uint32_t sadb_x_debug_rcv; - uint32_t sadb_x_debug_pfkey; - uint32_t sadb_x_debug_ipcomp; - uint32_t sadb_x_debug_verbose; - uint8_t sadb_x_debug_reserved[4]; -}; - -struct sadb_x_nat_t_type { - uint16_t sadb_x_nat_t_type_len; - uint16_t sadb_x_nat_t_type_exttype; - uint8_t sadb_x_nat_t_type_type; - uint8_t sadb_x_nat_t_type_reserved[3]; -}; -struct sadb_x_nat_t_port { - uint16_t sadb_x_nat_t_port_len; - uint16_t sadb_x_nat_t_port_exttype; - uint16_t sadb_x_nat_t_port_port; - uint16_t sadb_x_nat_t_port_reserved; -}; - -/* - * A protocol structure for passing through the transport level - * protocol. It contains more fields than are actually used/needed - * but it is this way to be compatible with the structure used in - * OpenBSD (http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/pfkeyv2.h) - */ -struct sadb_protocol { - uint16_t sadb_protocol_len; - uint16_t sadb_protocol_exttype; - uint8_t sadb_protocol_proto; - uint8_t sadb_protocol_direction; - uint8_t sadb_protocol_flags; - uint8_t sadb_protocol_reserved2; -}; - -#define SADB_EXT_RESERVED 0 -#define SADB_EXT_SA 1 -#define SADB_EXT_LIFETIME_CURRENT 2 -#define SADB_EXT_LIFETIME_HARD 3 -#define SADB_EXT_LIFETIME_SOFT 4 -#define SADB_EXT_ADDRESS_SRC 5 -#define SADB_EXT_ADDRESS_DST 6 -#define SADB_EXT_ADDRESS_PROXY 7 -#define SADB_EXT_KEY_AUTH 8 -#define SADB_EXT_KEY_ENCRYPT 9 -#define SADB_EXT_IDENTITY_SRC 10 -#define SADB_EXT_IDENTITY_DST 11 -#define SADB_EXT_SENSITIVITY 12 -#define SADB_EXT_PROPOSAL 13 -#define SADB_EXT_SUPPORTED_AUTH 14 -#define SADB_EXT_SUPPORTED_ENCRYPT 15 -#define SADB_EXT_SPIRANGE 16 -#define SADB_X_EXT_KMPRIVATE 17 -#define SADB_X_EXT_SATYPE2 18 -#ifdef KERNEL26_HAS_KAME_DUPLICATES -#define SADB_X_EXT_POLICY 18 -#endif -#define SADB_X_EXT_SA2 19 -#define SADB_X_EXT_ADDRESS_DST2 20 -#define SADB_X_EXT_ADDRESS_SRC_FLOW 21 -#define SADB_X_EXT_ADDRESS_DST_FLOW 22 -#define SADB_X_EXT_ADDRESS_SRC_MASK 23 -#define SADB_X_EXT_ADDRESS_DST_MASK 24 -#define SADB_X_EXT_DEBUG 25 -#define SADB_X_EXT_PROTOCOL 26 -#define SADB_X_EXT_NAT_T_TYPE 27 -#define SADB_X_EXT_NAT_T_SPORT 28 -#define SADB_X_EXT_NAT_T_DPORT 29 -#define SADB_X_EXT_NAT_T_OA 30 -#define SADB_EXT_MAX 30 - -/* SADB_X_DELFLOW required over and above SADB_X_SAFLAGS_CLEARFLOW */ -#define SADB_X_EXT_ADDRESS_DELFLOW \ - ( (1<" -.sp -.B "int portof(const ip_address *src);" -.br -.B "void setportof(int port, ip_address *dst);" -.br -.B "struct sockaddr *sockaddrof(ip_address *src);" -.br -.B "size_t sockaddrlenof(const ip_address *src);" -.SH DESCRIPTION -The -.B -internal type -.I ip_address -contains one of the -.I sockaddr -types internally. -\fIReliance on this feature is discouraged\fR, -but it may occasionally be necessary. -These functions provide low-level tools for this purpose. -.PP -.I Portof -and -.I setportof -respectively read and write the port-number field of the internal -.IR sockaddr . -The values are in network byte order. -.PP -.I Sockaddrof -returns a pointer to the internal -.IR sockaddr , -for passing to other functions. -.PP -.I Sockaddrlenof -reports the size of the internal -.IR sockaddr , -for use in storage allocation. -.SH SEE ALSO -inet(3), ipsec_initaddr(3) -.SH DIAGNOSTICS -.I Portof -returns -.BR \-1 , -.I sockaddrof -returns -.BR NULL , -and -.I sockaddrlenof -returns -.B 0 -if an unknown address family is found within the -.IR ip_address . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -These functions all depend on low-level details of the -.I ip_address -type, which are in principle subject to change. -Avoid using them unless really necessary. diff --git a/src/libfreeswan/portof.c b/src/libfreeswan/portof.c deleted file mode 100644 index c44b839f3..000000000 --- a/src/libfreeswan/portof.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * low-level ip_address ugliness - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - - portof - get the port field of an ip_address - */ -int /* network order */ -portof(src) -const ip_address *src; -{ - switch (src->u.v4.sin_family) { - case AF_INET: - return src->u.v4.sin_port; - break; - case AF_INET6: - return src->u.v6.sin6_port; - break; - default: - return -1; /* "can't happen" */ - break; - } -} - -/* - - setportof - set the port field of an ip_address - */ -void -setportof(port, dst) -int port; /* network order */ -ip_address *dst; -{ - switch (dst->u.v4.sin_family) { - case AF_INET: - dst->u.v4.sin_port = port; - break; - case AF_INET6: - dst->u.v6.sin6_port = port; - break; - } -} - -/* - - sockaddrof - get a pointer to the sockaddr hiding inside an ip_address - */ -struct sockaddr * -sockaddrof(src) -ip_address *src; -{ - switch (src->u.v4.sin_family) { - case AF_INET: - return (struct sockaddr *)&src->u.v4; - break; - case AF_INET6: - return (struct sockaddr *)&src->u.v6; - break; - default: - return NULL; /* "can't happen" */ - break; - } -} - -/* - - sockaddrlenof - get length of the sockaddr hiding inside an ip_address - */ -size_t /* 0 for error */ -sockaddrlenof(src) -const ip_address *src; -{ - switch (src->u.v4.sin_family) { - case AF_INET: - return sizeof(src->u.v4); - break; - case AF_INET6: - return sizeof(src->u.v6); - break; - default: - return 0; - break; - } -} diff --git a/src/libfreeswan/rangetoa.c b/src/libfreeswan/rangetoa.c deleted file mode 100644 index 704558248..000000000 --- a/src/libfreeswan/rangetoa.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * convert binary form of address range to ASCII - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - rangetoa - convert address range to ASCII - */ -size_t /* space needed for full conversion */ -rangetoa(addrs, format, dst, dstlen) -struct in_addr addrs[2]; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t len; - size_t rest; - int n; - char *p; - - switch (format) { - case 0: - break; - default: - return 0; - break; - } - - len = addrtoa(addrs[0], 0, dst, dstlen); - if (len < dstlen) - for (p = dst + len - 1, n = 3; len < dstlen && n > 0; - p++, len++, n--) - *p = '.'; - else - p = NULL; - if (len < dstlen) - rest = dstlen - len; - else { - if (dstlen > 0) - *(dst + dstlen - 1) = '\0'; - rest = 0; - } - - len += addrtoa(addrs[1], 0, p, rest); - - return len; -} diff --git a/src/libfreeswan/rangetosubnet.3 b/src/libfreeswan/rangetosubnet.3 deleted file mode 100644 index 100b42bd9..000000000 --- a/src/libfreeswan/rangetosubnet.3 +++ /dev/null @@ -1,58 +0,0 @@ -.TH IPSEC_RANGETOSUBNET 3 "8 Sept 2000" -.SH NAME -ipsec rangetosubnet \- convert address range to subnet -.SH SYNOPSIS -.B "#include " -.sp -.B "const char *rangetosubnet(const ip_address *start," -.ti +1c -.B "const ip_address *stop, ip_subnet *dst);" -.SH DESCRIPTION -.I Rangetosubnet -accepts two IP addresses which define an address range, -from -.I start -to -.I stop -inclusive, -and converts this to a subnet if possible. -The addresses must both be IPv4 or both be IPv6, -and the address family of the resulting subnet is the same. -.PP -.I Rangetosubnet -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.SH SEE ALSO -ipsec_initsubnet(3), ipsec_ttosubnet(3) -.SH DIAGNOSTICS -Fatal errors in -.I rangetosubnet -are: -mixed address families; -unknown address family; -.I start -and -.I stop -do not define a subnet. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The restriction of error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = rangetosubnet( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/rangetosubnet.c b/src/libfreeswan/rangetosubnet.c deleted file mode 100644 index 2a989300e..000000000 --- a/src/libfreeswan/rangetosubnet.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * express an address range as a subnet (if possible) - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - rangetosubnet - turn an address range into a subnet, if possible - * - * A range which is a valid subnet will have a network part which is the - * same in the from value and the to value, followed by a host part which - * is all 0 in the from value and all 1 in the to value. - */ -err_t -rangetosubnet(from, to, dst) -const ip_address *from; -const ip_address *to; -ip_subnet *dst; -{ - unsigned const char *fp; - unsigned const char *tp; - unsigned fb; - unsigned tb; - unsigned const char *f; - unsigned const char *t; - size_t n; - size_t n2; - int i; - int nnet; - unsigned m; - - if (addrtypeof(from) != addrtypeof(to)) - return "mismatched address types"; - n = addrbytesptr(from, &fp); - if (n == 0) - return "unknown address type"; - n2 = addrbytesptr(to, &tp); - if (n != n2) - return "internal size mismatch in rangetosubnet"; - - f = fp; - t = tp; - nnet = 0; - for (i = n; i > 0 && *f == *t; i--, f++, t++) - nnet += 8; - if (i > 0 && !(*f == 0x00 && *t == 0xff)) { /* mid-byte bdry. */ - fb = *f++; - tb = *t++; - i--; - m = 0x80; - while ((fb&m) == (tb&m)) { - fb &= ~m; - tb |= m; - m >>= 1; - nnet++; - } - if (fb != 0x00 || tb != 0xff) - return "not a valid subnet"; - } - for (; i > 0 && *f == 0x00 && *t == 0xff; i--, f++, t++) - continue; - - if (i != 0) - return "invalid subnet"; - - return initsubnet(from, nnet, 'x', dst); -} - - - -#ifdef RANGETOSUBNET_MAIN - -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - ip_address start; - ip_address stop; - ip_subnet sub; - char buf[100]; - const char *oops; - size_t n; - int af; - int i; - - if (argc == 2 && strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - if (argc < 3) { - fprintf(stderr, "Usage: %s [-6] start stop\n", argv[0]); - fprintf(stderr, " or: %s -r\n", argv[0]); - exit(2); - } - - af = AF_INET; - i = 1; - if (strcmp(argv[i], "-6") == 0) { - af = AF_INET6; - i++; - } - - oops = ttoaddr(argv[i], 0, af, &start); - if (oops != NULL) { - fprintf(stderr, "%s: start conversion failed: %s\n", argv[0], oops); - exit(1); - } - oops = ttoaddr(argv[i+1], 0, af, &stop); - if (oops != NULL) { - fprintf(stderr, "%s: stop conversion failed: %s\n", argv[0], oops); - exit(1); - } - oops = rangetosubnet(&start, &stop, &sub); - if (oops != NULL) { - fprintf(stderr, "%s: rangetosubnet failed: %s\n", argv[0], oops); - exit(1); - } - n = subnettot(&sub, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conversion", argv[0]); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - int family; - char *start; - char *stop; - char *output; /* NULL means error expected */ -} rtab[] = { - {4, "1.2.3.0", "1.2.3.255", "1.2.3.0/24"}, - {4, "1.2.3.0", "1.2.3.7", "1.2.3.0/29"}, - {4, "1.2.3.240", "1.2.3.255", "1.2.3.240/28"}, - {4, "0.0.0.0", "255.255.255.255", "0.0.0.0/0"}, - {4, "1.2.3.4", "1.2.3.4", "1.2.3.4/32"}, - {4, "1.2.3.0", "1.2.3.254", NULL}, - {4, "1.2.3.0", "1.2.3.126", NULL}, - {4, "1.2.3.0", "1.2.3.125", NULL}, - {4, "1.2.0.0", "1.2.255.255", "1.2.0.0/16"}, - {4, "1.2.0.0", "1.2.0.255", "1.2.0.0/24"}, - {4, "1.2.255.0", "1.2.255.255", "1.2.255.0/24"}, - {4, "1.2.255.0", "1.2.254.255", NULL}, - {4, "1.2.255.1", "1.2.255.255", NULL}, - {4, "1.2.0.1", "1.2.255.255", NULL}, - {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:ffff", "1:2:3:4:5:6:7:0/112"}, - {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:fff", "1:2:3:4:5:6:7:0/116"}, - {6, "1:2:3:4:5:6:7:f0", "1:2:3:4:5:6:7:ff", "1:2:3:4:5:6:7:f0/124"}, - {4, NULL, NULL, NULL}, -}; - -void -regress() -{ - struct rtab *r; - int status = 0; - ip_address start; - ip_address stop; - ip_subnet sub; - char buf[100]; - const char *oops; - size_t n; - int af; - - for (r = rtab; r->start != NULL; r++) { - af = (r->family == 4) ? AF_INET : AF_INET6; - oops = ttoaddr(r->start, 0, af, &start); - if (oops != NULL) { - printf("surprise failure converting `%s'\n", r->start); - exit(1); - } - oops = ttoaddr(r->stop, 0, af, &stop); - if (oops != NULL) { - printf("surprise failure converting `%s'\n", r->stop); - exit(1); - } - oops = rangetosubnet(&start, &stop, &sub); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s'-`%s' rangetosubnet failed: %s\n", - r->start, r->stop, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s'-`%s' rangetosubnet succeeded unexpectedly\n", - r->start, r->stop); - status = 1; - } else { - n = subnettot(&sub, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - printf("`%s'-`%s' subnettot failed: need %ld\n", - r->start, r->stop, (long)n); - status = 1; - } else if (strcmp(r->output, buf) != 0) { - printf("`%s'-`%s' gave `%s', expected `%s'\n", - r->start, r->stop, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* RANGETOSUBNET_MAIN */ diff --git a/src/libfreeswan/sameaddr.3 b/src/libfreeswan/sameaddr.3 deleted file mode 100644 index 62886bf1a..000000000 --- a/src/libfreeswan/sameaddr.3 +++ /dev/null @@ -1,164 +0,0 @@ -.TH IPSEC_ANYADDR 3 "28 Nov 2000" -.SH NAME -ipsec sameaddr \- are two addresses the same? -.br -ipsec addrcmp \- ordered comparison of addresses -.br -ipsec samesubnet \- are two subnets the same? -.br -ipsec addrinsubnet \- is an address within a subnet? -.br -ipsec subnetinsubnet \- is a subnet within another subnet? -.br -ipsec subnetishost \- is a subnet a single host? -.br -ipsec samesaid \- are two SA IDs the same? -.br -ipsec sameaddrtype \- are two addresses of the same address family? -.br -ipsec samesubnettype \- are two subnets of the same address family? -.SH SYNOPSIS -.B "#include -.sp -.B "int sameaddr(const ip_address *a, const ip_address *b);" -.br -.B "int addrcmp(const ip_address *a, const ip_address *b);" -.br -.B "int samesubnet(const ip_subnet *a, const ip_subnet *b);" -.br -.B "int addrinsubnet(const ip_address *a, const ip_subnet *s);" -.br -.B "int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);" -.br -.B "int subnetishost(const ip_subnet *s);" -.br -.B "int samesaid(const ip_said *a, const ip_said *b);" -.br -.B "int sameaddrtype(const ip_address *a, const ip_address *b);" -.br -.B "int samesubnettype(const ip_subnet *a, const ip_subnet *b);" -.SH DESCRIPTION -These functions do various comparisons and tests on the -.I ip_address -type and -.I ip_subnet -types. -.PP -.I Sameaddr -returns -non-zero -if addresses -.I a -and -.IR b -are identical, -and -.B 0 -otherwise. -Addresses of different families are never identical. -.PP -.I Addrcmp -returns -.BR \-1 , -.BR 0 , -or -.BR 1 -respectively -if address -.I a -is less than, equal to, or greater than -.IR b . -If they are not of the same address family, -they are never equal; -the ordering reported in this case is arbitrary -(and probably not useful) but consistent. -.PP -.I Samesubnet -returns -non-zero -if subnets -.I a -and -.IR b -are identical, -and -.B 0 -otherwise. -Subnets of different address families are never identical. -.PP -.I Addrinsubnet -returns -non-zero -if address -.I a -is within subnet -.IR s -and -.B 0 -otherwise. -An address is never within a -subnet of a different address family. -.PP -.I Subnetinsubnet -returns -non-zero -if subnet -.I a -is a subset of subnet -.IR b -and -.B 0 -otherwise. -A subnet is deemed to be a subset of itself. -A subnet is never a subset of another -subnet if their address families differ. -.PP -.I Subnetishost -returns -non-zero -if subnet -.I s -is in fact only a single host, -and -.B 0 -otherwise. -.PP -.I Samesaid -returns -non-zero -if SA IDs -.I a -and -.IR b -are identical, -and -.B 0 -otherwise. -.PP -.I Sameaddrtype -returns -non-zero -if addresses -.I a -and -.IR b -are of the same address family, -and -.B 0 -otherwise. -.PP -.I Samesubnettype -returns -non-zero -if subnets -.I a -and -.IR b -are of the same address family, -and -.B 0 -otherwise. -.SH SEE ALSO -inet(3), ipsec_initaddr(3) -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. diff --git a/src/libfreeswan/sameaddr.c b/src/libfreeswan/sameaddr.c deleted file mode 100644 index 47daaa4ee..000000000 --- a/src/libfreeswan/sameaddr.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * comparisons - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -static int samenbits(const ip_address *a, const ip_address *b, int n); - -/* - - addrcmp - compare two addresses - * Caution, the order of the tests is subtle: doing type test before - * size test can yield cases where ac. - */ -int /* like memcmp */ -addrcmp(a, b) -const ip_address *a; -const ip_address *b; -{ - int at = addrtypeof(a); - int bt = addrtypeof(b); - const unsigned char *ap; - const unsigned char *bp; - size_t as = addrbytesptr(a, &ap); - size_t bs = addrbytesptr(b, &bp); - size_t n = (as < bs) ? as : bs; /* min(as, bs) */ - int c = memcmp(ap, bp, n); - - if (c != 0) /* bytes differ */ - return (c < 0) ? -1 : 1; - if (as != bs) /* comparison incomplete: lexical order */ - return (as < bs) ? -1 : 1; - if (at != bt) /* bytes same but not same type: break tie */ - return (at < bt) ? -1 : 1; - return 0; -} - -/* - - sameaddr - are two addresses the same? - */ -int -sameaddr(a, b) -const ip_address *a; -const ip_address *b; -{ - return (addrcmp(a, b) == 0) ? 1 : 0; -} - -/* - - samesubnet - are two subnets the same? - */ -int -samesubnet(a, b) -const ip_subnet *a; -const ip_subnet *b; -{ - if (!sameaddr(&a->addr, &b->addr)) /* also does type check */ - return 0; - if (a->maskbits != b->maskbits) - return 0; - return 1; -} - -/* - - subnetishost - is a subnet in fact a single host? - */ -int -subnetishost(a) -const ip_subnet *a; -{ - return (a->maskbits == addrlenof(&a->addr)*8) ? 1 : 0; -} - -/* - - samesaid - are two SA IDs the same? - */ -int -samesaid(a, b) -const ip_said *a; -const ip_said *b; -{ - if (a->spi != b->spi) /* test first, most likely to be different */ - return 0; - if (!sameaddr(&a->dst, &b->dst)) - return 0; - if (a->proto != b->proto) - return 0; - return 1; -} - -/* - - sameaddrtype - do two addresses have the same type? - */ -int -sameaddrtype(a, b) -const ip_address *a; -const ip_address *b; -{ - return (addrtypeof(a) == addrtypeof(b)) ? 1 : 0; -} - -/* - - samesubnettype - do two subnets have the same type? - */ -int -samesubnettype(a, b) -const ip_subnet *a; -const ip_subnet *b; -{ - return (subnettypeof(a) == subnettypeof(b)) ? 1 : 0; -} - -/* - - addrinsubnet - is this address in this subnet? - */ -int -addrinsubnet(a, s) -const ip_address *a; -const ip_subnet *s; -{ - if (addrtypeof(a) != subnettypeof(s)) - return 0; - if (!samenbits(a, &s->addr, s->maskbits)) - return 0; - return 1; -} - -/* - - subnetinsubnet - is one subnet within another? - */ -int -subnetinsubnet(a, b) -const ip_subnet *a; -const ip_subnet *b; -{ - if (subnettypeof(a) != subnettypeof(b)) - return 0; - if (a->maskbits < b->maskbits) /* a is bigger than b */ - return 0; - if (!samenbits(&a->addr, &b->addr, b->maskbits)) - return 0; - return 1; -} - -/* - - samenbits - do two addresses have the same first n bits? - */ -static int -samenbits(a, b, nbits) -const ip_address *a; -const ip_address *b; -int nbits; -{ - const unsigned char *ap; - const unsigned char *bp; - size_t n; - int m; - - if (addrtypeof(a) != addrtypeof(b)) - return 0; /* arbitrary */ - n = addrbytesptr(a, &ap); - if (n == 0) - return 0; /* arbitrary */ - (void) addrbytesptr(b, &bp); - if (nbits > n*8) - return 0; /* "can't happen" */ - - for (; nbits >= 8 && *ap == *bp; nbits -= 8, ap++, bp++) - continue; - if (nbits >= 8) - return 0; - if (nbits > 0) { /* partial byte */ - m = ~(0xff >> nbits); - if ((*ap & m) != (*bp & m)) - return 0; - } - return 1; -} diff --git a/src/libfreeswan/satot.c b/src/libfreeswan/satot.c deleted file mode 100644 index a3feb1591..000000000 --- a/src/libfreeswan/satot.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * convert from binary form of SA ID to text - * Copyright (C) 2000, 2001 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -static struct typename { - char type; - char *name; -} typenames[] = { - { SA_AH, "ah" }, - { SA_ESP, "esp" }, - { SA_IPIP, "tun" }, - { SA_COMP, "comp" }, - { SA_INT, "int" }, - { 0, NULL } -}; - -/* - - satot - convert SA to text "ah507@1.2.3.4" - */ -size_t /* space needed for full conversion */ -satot(sa, format, dst, dstlen) -const ip_said *sa; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t len = 0; /* 0 means "not recognized yet" */ - int base; - int showversion; /* use delimiter to show IP version? */ - struct typename *tn; - char *p; - char *pre; - char buf[10+1+ULTOT_BUF+ADDRTOT_BUF]; - char unk[10]; - - switch (format) { - case 0: - base = 16; - showversion = 1; - break; - case 'f': - base = 17; - showversion = 1; - break; - case 'x': - base = 'x'; - showversion = 0; - break; - case 'd': - base = 10; - showversion = 0; - break; - default: - return 0; - break; - } - - pre = NULL; - for (tn = typenames; tn->name != NULL; tn++) - if (sa->proto == tn->type) { - pre = tn->name; - break; /* NOTE BREAK OUT */ - } - if (pre == NULL) { /* unknown protocol */ - strncpy(unk, "unk", sizeof(unk)); - (void) ultot((unsigned char)sa->proto, 10, unk+strlen(unk), - sizeof(unk)-strlen(unk)); - pre = unk; - } - - if (strcmp(pre, PASSTHROUGHTYPE) == 0 && - sa->spi == PASSTHROUGHSPI && - isunspecaddr(&sa->dst)) { - strncpy(buf, (addrtypeof(&sa->dst) == AF_INET) ? - PASSTHROUGH4NAME : - PASSTHROUGH6NAME, sizeof(buf)); - len = strlen(buf); - } - - if (sa->proto == SA_INT && addrtypeof(&sa->dst) == AF_INET && - isunspecaddr(&sa->dst)) { - switch (ntohl(sa->spi)) { - case SPI_PASS: p = "%pass"; break; - case SPI_DROP: p = "%drop"; break; - case SPI_REJECT: p = "%reject"; break; - case SPI_HOLD: p = "%hold"; break; - case SPI_TRAP: p = "%trap"; break; - case SPI_TRAPSUBNET: p = "%trapsubnet"; break; - default: p = NULL; break; - } - if (p != NULL) { - strncpy(buf, p, sizeof(buf)); - len = strlen(buf); - } - } - - if (len == 0) { /* general case needed */ - strncpy(buf, pre, sizeof(buf)); - len = strlen(buf); - if (showversion) { - *(buf+len) = (addrtypeof(&sa->dst) == AF_INET) ? '.' : - ':'; - len++; - *(buf+len) = '\0'; - } - len += ultot(ntohl(sa->spi), base, buf+len, sizeof(buf)-len); - *(buf+len-1) = '@'; - len += addrtot(&sa->dst, 0, buf+len, sizeof(buf)-len); - } - - if (dst != NULL) { - if (len > dstlen) - *(buf+dstlen-1) = '\0'; - strncpy(dst, buf, dstlen); - } - return len; -} diff --git a/src/libfreeswan/subnetof.3 b/src/libfreeswan/subnetof.3 deleted file mode 100644 index aacc76d2c..000000000 --- a/src/libfreeswan/subnetof.3 +++ /dev/null @@ -1,46 +0,0 @@ -.TH IPSEC_SUBNETOF 3 "11 June 2001" -.SH NAME -ipsec subnetof \- given Internet address and subnet mask, return subnet number -.br -ipsec hostof \- given Internet address and subnet mask, return host part -.br -ipsec broadcastof \- given Internet address and subnet mask, return broadcast address -.SH SYNOPSIS -.B "#include -.sp -.B "struct in_addr subnetof(struct in_addr addr," -.ti +1c -.B "struct in_addr mask);" -.br -.B "struct in_addr hostof(struct in_addr addr," -.ti +1c -.B "struct in_addr mask);" -.br -.B "struct in_addr broadcastof(struct in_addr addr," -.ti +1c -.B "struct in_addr mask);" -.SH DESCRIPTION -These functions are obsolete; see -.IR ipsec_networkof (3) -for their replacements. -.PP -.I Subnetof -takes an Internet -.I address -and a subnet -.I mask -and returns the network part of the address -(all in network byte order). -.I Hostof -similarly returns the host part, and -.I broadcastof -returns the broadcast address (all-1s convention) for the network. -.PP -These functions are provided to hide the Internet bit-munging inside -an API, in hopes of easing the eventual transition to IPv6. -.SH SEE ALSO -inet(3), ipsec_atosubnet(3) -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -Calling functions for this is more costly than doing it yourself. diff --git a/src/libfreeswan/subnetof.c b/src/libfreeswan/subnetof.c deleted file mode 100644 index ec9b8ec7d..000000000 --- a/src/libfreeswan/subnetof.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * minor network-address manipulation utilities - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - subnetof - given address and mask, return subnet part - */ -struct in_addr -subnetof(addr, mask) -struct in_addr addr; -struct in_addr mask; -{ - struct in_addr result; - - result.s_addr = addr.s_addr & mask.s_addr; - return result; -} - -/* - - hostof - given address and mask, return host part - */ -struct in_addr -hostof(addr, mask) -struct in_addr addr; -struct in_addr mask; -{ - struct in_addr result; - - result.s_addr = addr.s_addr & ~mask.s_addr; - return result; -} - -/* - - broadcastof - given (network) address and mask, return broadcast address - */ -struct in_addr -broadcastof(addr, mask) -struct in_addr addr; -struct in_addr mask; -{ - struct in_addr result; - - result.s_addr = addr.s_addr | ~mask.s_addr; - return result; -} diff --git a/src/libfreeswan/subnettoa.c b/src/libfreeswan/subnettoa.c deleted file mode 100644 index 694fa40da..000000000 --- a/src/libfreeswan/subnettoa.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * convert binary form of subnet description to ASCII - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - subnettoa - convert address and mask to ASCII "addr/mask" - * Output expresses the mask as a bit count if possible, else dotted decimal. - */ -size_t /* space needed for full conversion */ -subnettoa(addr, mask, format, dst, dstlen) -struct in_addr addr; -struct in_addr mask; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t len; - size_t rest; - int n; - char *p; - - switch (format) { - case 0: - break; - default: - return 0; - break; - } - - len = addrtoa(addr, 0, dst, dstlen); - if (len < dstlen) { - dst[len - 1] = '/'; - p = dst + len; - rest = dstlen - len; - } else { - p = NULL; - rest = 0; - } - - n = masktobits(mask); - if (n >= 0) - len += ultoa((unsigned long)n, 10, p, rest); - else - len += addrtoa(mask, 0, p, rest); - - return len; -} diff --git a/src/libfreeswan/subnettot.c b/src/libfreeswan/subnettot.c deleted file mode 100644 index 64d511ba2..000000000 --- a/src/libfreeswan/subnettot.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * convert binary form of subnet description to text - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - subnettot - convert subnet to text "addr/bitcount" - */ -size_t /* space needed for full conversion */ -subnettot(sub, format, dst, dstlen) -const ip_subnet *sub; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t len; - size_t rest; - char *p; - - switch (format) { - case 0: - break; - default: - return 0; - break; - } - - len = addrtot(&sub->addr, format, dst, dstlen); - if (len < dstlen) { - dst[len - 1] = '/'; - p = dst + len; - rest = dstlen - len; - } else { - p = NULL; - rest = 0; - } - - - len += ultoa((unsigned long)sub->maskbits, 10, p, rest); - - return len; -} diff --git a/src/libfreeswan/subnettypeof.c b/src/libfreeswan/subnettypeof.c deleted file mode 100644 index 96c283c04..000000000 --- a/src/libfreeswan/subnettypeof.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * extract parts of an ip_subnet, and related - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - subnettypeof - get the address type of an ip_subnet - */ -int -subnettypeof(src) -const ip_subnet *src; -{ - return src->addr.u.v4.sin_family; -} - -/* - - networkof - get the network address of a subnet - */ -void -networkof(src, dst) -const ip_subnet *src; -ip_address *dst; -{ - *dst = src->addr; -} - -/* - - maskof - get the mask of a subnet, as an address - */ -void -maskof(src, dst) -const ip_subnet *src; -ip_address *dst; -{ - int b; - unsigned char buf[16]; - size_t n = addrlenof(&src->addr); - unsigned char *p; - - if (src->maskbits > n*8 || n > sizeof(buf)) - return; /* "can't happen" */ - - p = buf; - for (b = src->maskbits; b >= 8; b -= 8) - *p++ = 0xff; - if (b != 0) - *p++ = (0xff << (8 - b)) & 0xff; - while (p - buf < n) - *p++ = 0; - - (void) initaddr(buf, n, addrtypeof(&src->addr), dst); -} - -/* - - masktocount - convert a mask, expressed as an address, to a bit count - */ -int /* -1 if not valid mask */ -masktocount(src) -const ip_address *src; -{ - int b; - unsigned const char *bp; - size_t n; - unsigned const char *p; - unsigned const char *stop; - - n = addrbytesptr(src, &bp); - if (n == 0) - return -1; - - p = bp; - stop = bp + n; - - n = 0; - while (p < stop && *p == 0xff) { - p++; - n += 8; - } - if (p < stop && *p != 0) { /* boundary in mid-byte */ - b = *p++; - while (b&0x80) { - b <<= 1; - n++; - } - if ((b&0xff) != 0) - return -1; /* bits not contiguous */ - } - while (p < stop && *p == 0) - p++; - - if (p != stop) - return -1; - - return n; -} diff --git a/src/libfreeswan/ttoaddr.3 b/src/libfreeswan/ttoaddr.3 deleted file mode 100644 index d43d2b16f..000000000 --- a/src/libfreeswan/ttoaddr.3 +++ /dev/null @@ -1,374 +0,0 @@ -.TH IPSEC_TTOADDR 3 "28 Sept 2001" -.SH NAME -ipsec ttoaddr, tnatoaddr, addrtot \- convert Internet addresses to and from text -.br -ipsec ttosubnet, subnettot \- convert subnet/mask text form to and from addresses -.SH SYNOPSIS -.B "#include -.sp -.B "const char *ttoaddr(const char *src, size_t srclen," -.ti +1c -.B "int af, ip_address *addr);" -.br -.B "const char *tnatoaddr(const char *src, size_t srclen," -.ti +1c -.B "int af, ip_address *addr);" -.br -.B "size_t addrtot(const ip_address *addr, int format," -.ti +1c -.B "char *dst, size_t dstlen);" -.sp -.B "const char *ttosubnet(const char *src, size_t srclen," -.ti +1c -.B "int af, ip_subnet *dst);" -.br -.B "size_t subnettot(const ip_subnet *sub, int format," -.ti +1c -.B "char *dst, size_t dstlen);" -.SH DESCRIPTION -.I Ttoaddr -converts a text-string name or numeric address into a binary address -(in network byte order). -.I Tnatoaddr -does the same conversion, -but the only text forms it accepts are -the ``official'' forms of -numeric address (dotted-decimal for IPv4, colon-hex for IPv6). -.I Addrtot -does the reverse conversion, from binary address back to a text form. -.I Ttosubnet -and -.I subnettot -do likewise for the ``address/mask'' form used to write a -specification of a subnet. -.PP -An IPv4 address is specified in text as a -dotted-decimal address (e.g. -.BR 1.2.3.4 ), -an eight-digit network-order hexadecimal number with the usual C prefix (e.g. -.BR 0x01020304 , -which is synonymous with -.BR 1.2.3.4 ), -an eight-digit host-order hexadecimal number with a -.B 0h -prefix (e.g. -.BR 0h01020304 , -which is synonymous with -.B 1.2.3.4 -on a big-endian host and -.B 4.3.2.1 -on a little-endian host), -a DNS name to be looked up via -.IR getaddrinfo (3), -or an old-style network name to be looked up via -.IR getnetbyname (3). -.PP -A dotted-decimal address may be incomplete, in which case -text-to-binary conversion implicitly appends -as many instances of -.B .0 -as necessary to bring it up to four components. -The components of a dotted-decimal address are always taken as -decimal, and leading zeros are ignored. -For example, -.B 10 -is synonymous with -.BR 10.0.0.0 , -and -.B 128.009.000.032 -is synonymous with -.BR 128.9.0.32 -(the latter example is verbatim from RFC 1166). -The result of applying -.I addrtot -to an IPv4 address is always complete and does not contain leading zeros. -.PP -Use of hexadecimal addresses is -.B strongly -.BR discouraged ; -they are included only to save hassles when dealing with -the handful of perverted programs which already print -network addresses in hexadecimal. -.PP -An IPv6 address is specified in text with -colon-hex notation (e.g. -.BR 0:56:78ab:22:33:44:55:66 ), -colon-hex with -.B :: -abbreviating at most one subsequence of multiple zeros (e.g. -.BR 99:ab::54:068 , -which is synonymous with -.BR 99:ab:0:0:0:0:54:68 ), -or a DNS name to be looked up via -.IR getaddrinfo (3). -The result of applying -.I addrtot -to an IPv6 address will use -.B :: -abbreviation if possible, -and will not contain leading zeros. -.PP -The letters in hexadecimal -may be uppercase or lowercase or any mixture thereof. -.PP -DNS names may be complete (optionally terminated with a ``.'') -or incomplete, and are looked up as specified by local system configuration -(see -.IR resolver (5)). -The first value returned by -.IR getaddrinfo (3) -is used, -so with current DNS implementations, -the result when the name corresponds to more than one address is -difficult to predict. -IPv4 name lookup resorts to -.IR getnetbyname (3) -only if -.IR getaddrinfo (3) -fails. -.PP -A subnet specification is of the form \fInetwork\fB/\fImask\fR. -The -.I network -and -.I mask -can be any form acceptable to -.IR ttoaddr . -In addition, and preferably, the -.I mask -can be a decimal integer (leading zeros ignored) giving a bit count, -in which case -it stands for a mask with that number of high bits on and all others off -(e.g., -.B 24 -in IPv4 means -.BR 255.255.255.0 ). -In any case, the mask must be contiguous -(a sequence of high bits on and all remaining low bits off). -As a special case, the subnet specification -.B %default -is a synonym for -.B 0.0.0.0/0 -or -.B ::/0 -in IPv4 or IPv6 respectively. -.PP -.I Ttosubnet -ANDs the mask with the address before returning, -so that any non-network bits in the address are turned off -(e.g., -.B 10.1.2.3/24 -is synonymous with -.BR 10.1.2.0/24 ). -.I Subnettot -always generates the decimal-integer-bit-count -form of the mask, -with no leading zeros. -.PP -The -.I srclen -parameter of -.I ttoaddr -and -.I ttosubnet -specifies the length of the text string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I af -parameter of -.I ttoaddr -and -.I ttosubnet -specifies the address family of interest. -It should be either -.B AF_INET -or -.BR AF_INET6 . -.PP -The -.I dstlen -parameter of -.I addrtot -and -.I subnettot -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.I freeswan.h -header file defines constants, -.B ADDRTOT_BUF -and -.BR SUBNETTOT_BUF , -which are the sizes of buffers just large enough for worst-case results. -.PP -The -.I format -parameter of -.I addrtot -and -.I subnettot -specifies what format is to be used for the conversion. -The value -.B 0 -(not the character -.BR '0' , -but a zero value) -specifies a reasonable default, -and is in fact the only format currently available in -.IR subnettot . -.I Addrtot -also accepts format values -.B 'r' -(signifying a text form suitable for DNS reverse lookups, -e.g. -.B 4.3.2.1.IN-ADDR.ARPA. -for IPv4 and -RFC 2874 format for IPv6), -and -.B 'R' -(signifying an alternate reverse-lookup form, -an error for IPv4 and RFC 1886 format for IPv6). -Reverse-lookup names always end with a ``.''. -.PP -The text-to-binary functions return NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -The binary-to-text functions return -.B 0 -for a failure, and otherwise -always return the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.SH SEE ALSO -inet(3) -.SH DIAGNOSTICS -Fatal errors in -.I ttoaddr -are: -empty input; -unknown address family; -attempt to allocate temporary storage for a very long name failed; -name lookup failed; -syntax error in dotted-decimal or colon-hex form; -dotted-decimal or colon-hex component too large. -.PP -Fatal errors in -.I ttosubnet -are: -no -.B / -in -.IR src ; -.I ttoaddr -error in conversion of -.I network -or -.IR mask ; -bit-count mask too big; -mask non-contiguous. -.PP -Fatal errors in -.I addrtot -and -.I subnettot -are: -unknown format. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The interpretation of incomplete dotted-decimal addresses -(e.g. -.B 10/24 -means -.BR 10.0.0.0/24 ) -differs from that of some older conversion -functions, e.g. those of -.IR inet (3). -The behavior of the older functions has never been -particularly consistent or particularly useful. -.PP -Ignoring leading zeros in dotted-decimal components and bit counts -is arguably the most useful behavior in this application, -but it might occasionally cause confusion with the historical use of leading -zeros to denote octal numbers. -.PP -.I Ttoaddr -does not support the mixed colon-hex-dotted-decimal -convention used to embed an IPv4 address in an IPv6 address. -.PP -.I Addrtot -always uses the -.B :: -abbreviation (which can appear only once in an address) for the -.I first -sequence of multiple zeros in an IPv6 address. -One can construct addresses (unlikely ones) in which this is suboptimal. -.PP -.I Addrtot -.B 'r' -conversion of an IPv6 address uses lowercase hexadecimal, -not the uppercase used in RFC 2874's examples. -It takes careful reading of RFCs 2874, 2673, and 2234 to realize -that lowercase is technically legitimate here, -and there may be software which botches this -and hence would have trouble with lowercase hex. -.PP -Possibly -.I subnettot -ought to recognize the -.B %default -case and generate that string as its output. -Currently it doesn't. -.PP -It is barely possible that somebody, somewhere, -might have a legitimate use for non-contiguous subnet masks. -.PP -.IR Getnetbyname (3) -is a historical dreg. -.PP -.I Tnatoaddr -probably should enforce completeness of dotted-decimal addresses. -.PP -The restriction of text-to-binary error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The text-to-binary error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = ttoaddr( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/ttoaddr.c b/src/libfreeswan/ttoaddr.c deleted file mode 100644 index 234c9d8e7..000000000 --- a/src/libfreeswan/ttoaddr.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * conversion from text forms of addresses to internal ones - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - * Legal ASCII characters in a domain name. Underscore technically is not, - * but is a common misunderstanding. Non-ASCII characters are simply - * exempted from checking at the moment, to allow for UTF-8 encoded stuff; - * the purpose of this check is merely to catch blatant errors. - */ -static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_."; -#define ISASCII(c) (((c) & 0x80) == 0) - -static err_t tryname(const char *, size_t, int, int, ip_address *); -static err_t tryhex(const char *, size_t, int, ip_address *); -static err_t trydotted(const char *, size_t, ip_address *); -static err_t getbyte(const char **, const char *, int *); -static err_t colon(const char *, size_t, ip_address *); -static err_t getpiece(const char **, const char *, unsigned *); - -/* - - ttoaddr - convert text name or dotted-decimal address to binary address - */ -err_t /* NULL for success, else string literal */ -ttoaddr(src, srclen, af, dst) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -int af; /* address family */ -ip_address *dst; -{ - err_t oops; -# define HEXLEN 10 /* strlen("0x11223344") */ - int nultermd; - - if (srclen == 0) { - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - nultermd = 1; - } else - nultermd = 0; /* at least, not *known* to be terminated */ - - switch (af) { - case AF_INET: - case AF_INET6: - case 0: /* guess */ - break; - - default: - return "invalid address family"; - } - - if (af == AF_INET && srclen == HEXLEN && *src == '0') { - if (*(src+1) == 'x' || *(src+1) == 'X') - return tryhex(src+2, srclen-2, 'x', dst); - if (*(src+1) == 'h' || *(src+1) == 'H') - return tryhex(src+2, srclen-2, 'h', dst); - } - - if (memchr(src, ':', srclen) != NULL) { - if(af == 0) - { - af = AF_INET6; - } - - if (af != AF_INET6) - return "non-ipv6 address may not contain `:'"; - return colon(src, srclen, dst); - } - - if (af == 0 || af == AF_INET) { - oops = trydotted(src, srclen, dst); - if (oops == NULL) - return NULL; /* it worked */ - if (*oops != '?') - return oops; /* probably meant as d-d */ - } - - return tryname(src, srclen, nultermd, af, dst); -} - -/* - - tnatoaddr - convert text numeric address (only) to binary address - */ -err_t /* NULL for success, else string literal */ -tnatoaddr(src, srclen, af, dst) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -int af; /* address family */ -ip_address *dst; -{ - err_t oops; - - if (srclen == 0) { - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - } - - switch (af) { - case 0: /* guess */ - oops = colon(src, srclen, dst); - if(oops == NULL) - { - return NULL; - } - oops = trydotted(src, srclen, dst); - if(oops == NULL) - { - return NULL; - } - return "does not appear to be either IPv4 or IPv6 numeric address"; - break; - - case AF_INET6: - return colon(src, srclen, dst); - break; - case AF_INET: - oops = trydotted(src, srclen, dst); - if (oops == NULL) - return NULL; /* it worked */ - if (*oops != '?') - return oops; /* probably meant as d-d */ - return "does not appear to be numeric address"; - break; - default: - return "unknown address family in tnatoaddr"; - break; - } -} - -/* - - tryname - try it as a name - * Slightly complicated by lack of reliable NUL termination in source. - */ -static err_t -tryname(src, srclen, nultermd, af, dst) -const char *src; -size_t srclen; -int nultermd; /* is it known to be NUL-terminated? */ -int af; -ip_address *dst; -{ - struct addrinfo hints, *res; - struct netent *ne = NULL; - char namebuf[100]; /* enough for most DNS names */ - const char *cp; - char *p = namebuf; - unsigned char *addr = NULL; - size_t n; - int error; - err_t err = NULL; - - for (cp = src, n = srclen; n > 0; cp++, n--) - if (ISASCII(*cp) && strchr(namechars, *cp) == NULL) - return "illegal (non-DNS-name) character in name"; - - if (nultermd) - cp = src; - else { - if (srclen+1 > sizeof(namebuf)) { - p = (char *) MALLOC(srclen+1); - if (p == NULL) - return "unable to get temporary space for name"; - } - p[0] = '\0'; /* strncpy semantics are wrong */ - strncat(p, src, srclen); - cp = (const char *)p; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = af; - error = getaddrinfo(cp, NULL, &hints, &res); - if (error != 0) - { /* getaddrinfo failed, try getnetbyname */ - if (af == AF_INET) - { - ne = getnetbyname(cp); - if (ne != NULL) - { - ne->n_net = htonl(ne->n_net); - addr = (unsigned char*)&ne->n_net; - err = initaddr(addr, sizeof(ne->n_net), af, dst); - } - } - } - else - { - struct addrinfo *r = res; - while (r) - { - size_t addr_len; - switch (r->ai_family) - { - case AF_INET: - { - struct sockaddr_in *in = (struct sockaddr_in*)r->ai_addr; - addr_len = 4; - addr = (unsigned char*)&in->sin_addr.s_addr; - break; - } - case AF_INET6: - { - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)r->ai_addr; - addr_len = 16; - addr = (unsigned char*)&in6->sin6_addr.s6_addr; - break; - } - default: - { /* unknown family, try next result */ - r = r->ai_next; - continue; - } - } - err = initaddr(addr, addr_len, r->ai_family, dst); - break; - } - freeaddrinfo(res); - } - - if (p != namebuf) - { - FREE(p); - } - - if (addr == NULL) - { - return "does not look numeric and name lookup failed"; - } - - return err; -} - -/* - - tryhex - try conversion as an eight-digit hex number (AF_INET only) - */ -static err_t -tryhex(src, srclen, flavor, dst) -const char *src; -size_t srclen; /* should be 8 */ -int flavor; /* 'x' for network order, 'h' for host order */ -ip_address *dst; -{ - err_t oops; - unsigned long ul; - union { - uint32_t addr; - unsigned char buf[4]; - } u; - - if (srclen != 8) - return "internal error, tryhex called with bad length"; - - oops = ttoul(src, srclen, 16, &ul); - if (oops != NULL) - return oops; - - u.addr = (flavor == 'h') ? ul : htonl(ul); - return initaddr(u.buf, sizeof(u.buf), AF_INET, dst); -} - -/* - - trydotted - try conversion as dotted decimal (AF_INET only) - * - * If the first char of a complaint is '?', that means "didn't look like - * dotted decimal at all". - */ -static err_t -trydotted(src, srclen, dst) -const char *src; -size_t srclen; -ip_address *dst; -{ - const char *stop = src + srclen; /* just past end */ - int byte; - err_t oops; -# define NBYTES 4 - unsigned char buf[NBYTES]; - int i; - - memset(buf, 0, sizeof(buf)); - for (i = 0; i < NBYTES && src < stop; i++) { - oops = getbyte(&src, stop, &byte); - if (oops != NULL) { - if (*oops != '?') - return oops; /* bad number */ - if (i > 1) - return oops+1; /* failed number */ - return oops; /* with leading '?' */ - } - buf[i] = byte; - if (i < 3 && src < stop && *src++ != '.') { - if (i == 0) - return "?syntax error in dotted-decimal address"; - else - return "syntax error in dotted-decimal address"; - } - } - if (src != stop) - return "extra garbage on end of dotted-decimal address"; - - return initaddr(buf, sizeof(buf), AF_INET, dst); -} - -/* - - getbyte - try to scan a byte in dotted decimal - * A subtlety here is that all this arithmetic on ASCII digits really is - * highly portable -- ANSI C guarantees that digits 0-9 are contiguous. - * It's easier to just do it ourselves than set up for a call to ttoul(). - * - * If the first char of a complaint is '?', that means "didn't look like a - * number at all". - */ -err_t -getbyte(srcp, stop, retp) -const char **srcp; /* *srcp is updated */ -const char *stop; /* first untouchable char */ -int *retp; /* return-value pointer */ -{ - char c; - const char *p; - int no; - - if (*srcp >= stop) - return "?empty number in dotted-decimal address"; - - no = 0; - p = *srcp; - while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') { - no = no*10 + (c - '0'); - p++; - } - if (p == *srcp) - return "?non-numeric component in dotted-decimal address"; - *srcp = p; - if (no > 255) - return "byte overflow in dotted-decimal address"; - *retp = no; - return NULL; -} - -/* - - colon - convert IPv6 "numeric" address - */ -static err_t -colon(src, srclen, dst) -const char *src; -size_t srclen; /* known to be >0 */ -ip_address *dst; -{ - const char *stop = src + srclen; /* just past end */ - unsigned piece = 0; - int gapat; /* where was empty piece seen */ - err_t oops; -# define NPIECES 8 - unsigned char buf[NPIECES*2]; /* short may have wrong byte order */ - int i; - int j; -# define IT "IPv6 numeric address" - int naftergap; - - /* leading or trailing :: becomes single empty field */ - if (*src == ':') { /* legal only if leading :: */ - if (srclen == 1 || *(src+1) != ':') - return "illegal leading `:' in " IT; - if (srclen == 2) { - unspecaddr(AF_INET6, dst); - return NULL; - } - src++; /* past first but not second */ - srclen--; - } - if (*(stop-1) == ':') { /* legal only if trailing :: */ - if (srclen == 1 || *(stop-2) != ':') - return "illegal trailing `:' in " IT; - srclen--; /* leave one */ - } - - gapat = -1; - for (i = 0; i < NPIECES && src < stop; i++) { - oops = getpiece(&src, stop, &piece); - if (oops != NULL && *oops == ':') { /* empty field */ - if (gapat >= 0) - return "more than one :: in " IT; - gapat = i; - } else if (oops != NULL) - return oops; - buf[2*i] = piece >> 8; - buf[2*i + 1] = piece & 0xff; - if (i < NPIECES-1) { /* there should be more input */ - if (src == stop && gapat < 0) - return IT " ends prematurely"; - if (src != stop && *src++ != ':') - return "syntax error in " IT; - } - } - if (src != stop) - return "extra garbage on end of " IT; - - if (gapat < 0 && i < NPIECES) /* should have been caught earlier */ - return "incomplete " IT " (internal error)"; - if (gapat >= 0 && i == NPIECES) - return "non-abbreviating empty field in " IT; - if (gapat >= 0) { - naftergap = i - (gapat + 1); - for (i--, j = NPIECES-1; naftergap > 0; i--, j--, naftergap--) { - buf[2*j] = buf[2*i]; - buf[2*j + 1] = buf[2*i + 1]; - } - for (; j >= gapat; j--) - buf[2*j] = buf[2*j + 1] = 0; - } - - return initaddr(buf, sizeof(buf), AF_INET6, dst); -} - -/* - - getpiece - try to scan one 16-bit piece of an IPv6 address - */ -err_t /* ":" means "empty field seen" */ -getpiece(srcp, stop, retp) -const char **srcp; /* *srcp is updated */ -const char *stop; /* first untouchable char */ -unsigned *retp; /* return-value pointer */ -{ - const char *p; -# define NDIG 4 - int d; - unsigned long ret; - err_t oops; - - if (*srcp >= stop || **srcp == ':') { /* empty field */ - *retp = 0; - return ":"; - } - - p = *srcp; - d = 0; - while (p < stop && d < NDIG && isxdigit(*p)) { - p++; - d++; - } - if (d == 0) - return "non-hex field in IPv6 numeric address"; - if (p < stop && d == NDIG && isxdigit(*p)) - return "field in IPv6 numeric address longer than 4 hex digits"; - - oops = ttoul(*srcp, d, 16, &ret); - if (oops != NULL) /* shouldn't happen, really... */ - return oops; - - *srcp = p; - *retp = ret; - return NULL; -} diff --git a/src/libfreeswan/ttodata.3 b/src/libfreeswan/ttodata.3 deleted file mode 100644 index 8f4b1ec93..000000000 --- a/src/libfreeswan/ttodata.3 +++ /dev/null @@ -1,280 +0,0 @@ -.TH IPSEC_TTODATA 3 "16 August 2003" -.SH NAME -ipsec ttodata, datatot \- convert binary data bytes from and to text formats -.SH SYNOPSIS -.B "#include " -.sp -.B "const char *ttodata(const char *src, size_t srclen," -.ti +1c -.B "int base, char *dst, size_t dstlen, size_t *lenp);" -.br -.B "const char *ttodatav(const char *src, size_t srclen," -.ti +1c -.B "int base, char *dst, size_t dstlen, size_t *lenp," -.ti +1c -.B "char *errp, size_t errlen, int flags);" -.br -.B "size_t datatot(const char *src, size_t srclen," -.ti +1c -.B "int format, char *dst, size_t dstlen);" -.SH DESCRIPTION -.IR Ttodata , -.IR ttodatav , -and -.I datatot -convert arbitrary binary data (e.g. encryption or authentication keys) -from and to more-or-less human-readable text formats. -.PP -Currently supported formats are hexadecimal, base64, and characters. -.PP -A hexadecimal text value begins with a -.B 0x -(or -.BR 0X ) -prefix and continues with two-digit groups -of hexadecimal digits (0-9, and a-f or A-F), -each group encoding the value of one binary byte, high-order digit first. -A single -.B _ -(underscore) -between consecutive groups is ignored, permitting punctuation to improve -readability; doing this every eight digits seems about right. -.PP -A base64 text value begins with a -.B 0s -(or -.BR 0S ) -prefix -and continues with four-digit groups of base64 digits (A-Z, a-z, 0-9, +, and /), -each group encoding the value of three binary bytes as described in -section 6.8 of RFC 2045. -If -.B flags -has the -.B TTODATAV_IGNORESPACE -bit on, blanks are ignore (after the prefix). -Note that the last one or two digits of a base64 group can be -.B = -to indicate that fewer than three binary bytes are encoded. -.PP -A character text value begins with a -.B 0t -(or -.BR 0T ) -prefix -and continues with text characters, each being the value of one binary byte. -.PP -All these functions basically copy data from -.I src -(whose size is specified by -.IR srclen ) -to -.I dst -(whose size is specified by -.IR dstlen ), -doing the conversion en route. -If the result will not fit in -.IR dst , -it is truncated; -under no circumstances are more than -.I dstlen -bytes of result written to -.IR dst . -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result bytes are written at all. -.PP -The -.I base -parameter of -.I ttodata -and -.I ttodatav -specifies what format the input is in; -normally it should be -.B 0 -to signify that this gets figured out from the prefix. -Values of -.BR 16 , -.BR 64 , -and -.BR 256 -respectively signify hexadecimal, base64, and character-text formats -without prefixes. -.PP -The -.I format -parameter of -.IR datatot , -a single character used as a type code, -specifies which text format is wanted. -The value -.B 0 -(not ASCII -.BR '0' , -but a zero value) specifies a reasonable default. -Other currently-supported values are: -.RS 2 -.TP 4 -.B 'x' -continuous lower-case hexadecimal with a -.B 0x -prefix -.TP -.B 'h' -lower-case hexadecimal with a -.B 0x -prefix and a -.B _ -every eight digits -.TP -.B ':' -lower-case hexadecimal with no prefix and a -.B : -(colon) every two digits -.TP -.B 16 -lower-case hexadecimal with no prefix or -.B _ -.TP -.B 's' -continuous base64 with a -.B 0s -prefix -.TP -.B 64 -continuous base64 with no prefix -.RE -.PP -The default format is currently -.BR 'h' . -.PP -.I Ttodata -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -On success, -if and only if -.I lenp -is non-NULL, -.B *lenp -is set to the number of bytes required to contain the full untruncated result. -It is the caller's responsibility to check this against -.I dstlen -to determine whether he has obtained a complete result. -The -.B *lenp -value is correct even if -.I dstlen -is zero, which offers a way to determine how much space would be needed -before having to allocate any. -.PP -.I Ttodatav -is just like -.I ttodata -except that in certain cases, -if -.I errp -is non-NULL, -the buffer pointed to by -.I errp -(whose length is given by -.IR errlen ) -is used to hold a more detailed error message. -The return value is NULL for success, -and is either -.I errp -or a pointer to a string literal for failure. -If the size of the error-message buffer is -inadequate for the desired message, -.I ttodatav -will fall back on returning a pointer to a literal string instead. -The -.I freeswan.h -header file defines a constant -.B TTODATAV_BUF -which is the size of a buffer large enough for worst-case results. -.PP -The normal return value of -.IR datatot -is the number of bytes required -to contain the full untruncated result. -It is the caller's responsibility to check this against -.I dstlen -to determine whether he has obtained a complete result. -The return value is correct even if -.I dstlen -is zero, which offers a way to determine how much space would be needed -before having to allocate any. -A return value of -.B 0 -signals a fatal error of some kind -(see DIAGNOSTICS). -.PP -A zero value for -.I srclen -in -.I ttodata -(but not -.IR datatot !) -is synonymous with -.BR strlen(src) . -A non-zero -.I srclen -in -.I ttodata -must not include the terminating NUL. -.PP -Unless -.I dstlen -is zero, -the result supplied by -.I datatot -is always NUL-terminated, -and its needed-size return value includes space for the terminating NUL. -.PP -Several obsolete variants of these functions -.RI ( atodata , -.IR datatoa , -.IR atobytes , -and -.IR bytestoa ) -are temporarily also supported. -.SH SEE ALSO -sprintf(3), ipsec_atoaddr(3) -.SH DIAGNOSTICS -Fatal errors in -.I ttodata -and -.I ttodatav -are: -unknown characters in the input; -unknown or missing prefix; -unknown base; -incomplete digit group; -non-zero padding in a base64 less-than-three-bytes digit group; -zero-length input. -.PP -Fatal errors in -.I datatot -are: -unknown format code; -zero-length input. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -.I Datatot -should have a format code to produce character-text output. -.PP -The -.B 0s -and -.B 0t -prefixes are the author's inventions and are not a standard -of any kind. -They have been chosen to avoid collisions with existing practice -(some C implementations use -.B 0b -for binary) -and possible confusion with unprefixed hexadecimal. diff --git a/src/libfreeswan/ttodata.c b/src/libfreeswan/ttodata.c deleted file mode 100644 index ef3717797..000000000 --- a/src/libfreeswan/ttodata.c +++ /dev/null @@ -1,720 +0,0 @@ -/* - * convert from text form of arbitrary data (e.g., keys) to binary - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* converters and misc */ -static int unhex(const char *, char *, size_t); -static int unb64(const char *, char *, size_t); -static int untext(const char *, char *, size_t); -static const char *badch(const char *, int, char *, size_t); - -/* internal error codes for converters */ -#define SHORT (-2) /* internal buffer too short */ -#define BADPAD (-3) /* bad base64 padding */ -#define BADCH0 (-4) /* invalid character 0 */ -#define BADCH1 (-5) /* invalid character 1 */ -#define BADCH2 (-6) /* invalid character 2 */ -#define BADCH3 (-7) /* invalid character 3 */ -#define BADOFF(code) (BADCH0-(code)) - -/* - - ttodatav - convert text to data, with verbose error reports - * If some of this looks slightly odd, it's because it has changed - * repeatedly (from the original atodata()) without a major rewrite. - */ -const char * /* NULL on success, else literal or errp */ -ttodatav(src, srclen, base, dst, dstlen, lenp, errp, errlen, flags) -const char *src; -size_t srclen; /* 0 means apply strlen() */ -int base; /* 0 means figure it out */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -size_t *lenp; /* where to record length (NULL is nowhere) */ -char *errp; /* error buffer */ -size_t errlen; -unsigned int flags; -{ - size_t ingroup; /* number of input bytes converted at once */ - char buf[4]; /* output from conversion */ - int nbytes; /* size of output */ - int (*decode)(const char *, char *, size_t); - char *stop; - int ndone; - int i; - int underscoreok; - int skipSpace = 0; - - if (srclen == 0) - srclen = strlen(src); - if (dstlen == 0) - dst = buf; /* point it somewhere valid */ - stop = dst + dstlen; - - if (base == 0) { - if (srclen < 2) - return "input too short to be valid"; - if (*src++ != '0') - return "input does not begin with format prefix"; - switch (*src++) { - case 'x': - case 'X': - base = 16; - break; - case 's': - case 'S': - base = 64; - break; - case 't': - case 'T': - base = 256; - break; - default: - return "unknown format prefix"; - } - srclen -= 2; - } - switch (base) { - case 16: - decode = unhex; - underscoreok = 1; - ingroup = 2; - break; - case 64: - decode = unb64; - underscoreok = 0; - ingroup = 4; - if(flags & TTODATAV_IGNORESPACE) { - skipSpace = 1; - } - break; - - case 256: - decode = untext; - ingroup = 1; - underscoreok = 0; - break; - default: - return "unknown base"; - } - - /* proceed */ - ndone = 0; - while (srclen > 0) { - char stage[4]; /* staging area for group */ - size_t sl = 0; - - /* Grab ingroup characters into stage, - * squeezing out blanks if we are supposed to ignore them. - */ - for (sl = 0; sl < ingroup; src++, srclen--) { - if (srclen == 0) - return "input ends in mid-byte, perhaps truncated"; - else if (!(skipSpace && (*src == ' ' || *src == '\t'))) - stage[sl++] = *src; - } - - nbytes = (*decode)(stage, buf, sizeof(buf)); - switch (nbytes) { - case BADCH0: - case BADCH1: - case BADCH2: - case BADCH3: - return badch(stage, nbytes, errp, errlen); - case SHORT: - return "internal buffer too short (\"can't happen\")"; - case BADPAD: - return "bad (non-zero) padding at end of base64 input"; - } - if (nbytes <= 0) - return "unknown internal error"; - for (i = 0; i < nbytes; i++) { - if (dst < stop) - *dst++ = buf[i]; - ndone++; - } - while (srclen >= 1 && skipSpace && (*src == ' ' || *src == '\t')){ - src++; - srclen--; - } - if (underscoreok && srclen > 1 && *src == '_') { - /* srclen > 1 means not last character */ - src++; - srclen--; - } - } - - if (ndone == 0) - return "no data bytes specified by input"; - if (lenp != NULL) - *lenp = ndone; - return NULL; -} - -/* - - ttodata - convert text to data - */ -const char * /* NULL on success, else literal */ -ttodata(src, srclen, base, dst, dstlen, lenp) -const char *src; -size_t srclen; /* 0 means apply strlen() */ -int base; /* 0 means figure it out */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -size_t *lenp; /* where to record length (NULL is nowhere) */ -{ - return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL, - (size_t)0, TTODATAV_SPACECOUNTS); -} - -/* - - atodata - convert ASCII to data - * backward-compatibility interface - */ -size_t /* 0 for failure, true length for success */ -atodata(src, srclen, dst, dstlen) -const char *src; -size_t srclen; -char *dst; -size_t dstlen; -{ - size_t len; - const char *err; - - err = ttodata(src, srclen, 0, dst, dstlen, &len); - if (err != NULL) - return 0; - return len; -} - -/* - - atobytes - convert ASCII to data bytes - * another backward-compatibility interface - */ -const char * -atobytes(src, srclen, dst, dstlen, lenp) -const char *src; -size_t srclen; -char *dst; -size_t dstlen; -size_t *lenp; -{ - return ttodata(src, srclen, 0, dst, dstlen, lenp); -} - -/* - - unhex - convert two ASCII hex digits to byte - */ -static int /* number of result bytes, or error code */ -unhex(src, dst, dstlen) -const char *src; /* known to be full length */ -char *dst; -size_t dstlen; /* not large enough is a failure */ -{ - char *p; - unsigned byte; - static char hex[] = "0123456789abcdef"; - - if (dstlen < 1) - return SHORT; - - p = strchr(hex, *src); - if (p == NULL) - p = strchr(hex, tolower(*src)); - if (p == NULL) - return BADCH0; - byte = (p - hex) << 4; - src++; - - p = strchr(hex, *src); - if (p == NULL) - p = strchr(hex, tolower(*src)); - if (p == NULL) - return BADCH1; - byte |= (p - hex); - - *dst = byte; - return 1; -} - -/* - - unb64 - convert four ASCII base64 digits to three bytes - * Note that a base64 digit group is padded out with '=' if it represents - * less than three bytes: one byte is dd==, two is ddd=, three is dddd. - */ -static int /* number of result bytes, or error code */ -unb64(src, dst, dstlen) -const char *src; /* known to be full length */ -char *dst; -size_t dstlen; -{ - char *p; - unsigned byte1; - unsigned byte2; - static char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - if (dstlen < 3) - return SHORT; - - p = strchr(base64, *src++); - - if (p == NULL) - return BADCH0; - byte1 = (p - base64) << 2; /* first six bits */ - - p = strchr(base64, *src++); - if (p == NULL) { - return BADCH1; - } - - byte2 = p - base64; /* next six: two plus four */ - *dst++ = byte1 | (byte2 >> 4); - byte1 = (byte2 & 0xf) << 4; - - p = strchr(base64, *src++); - if (p == NULL) { - if (*(src-1) == '=' && *src == '=') { - if (byte1 != 0) /* bad padding */ - return BADPAD; - return 1; - } - return BADCH2; - } - - byte2 = p - base64; /* next six: four plus two */ - *dst++ = byte1 | (byte2 >> 2); - byte1 = (byte2 & 0x3) << 6; - - p = strchr(base64, *src++); - if (p == NULL) { - if (*(src-1) == '=') { - if (byte1 != 0) /* bad padding */ - return BADPAD; - return 2; - } - return BADCH3; - } - byte2 = p - base64; /* last six */ - *dst++ = byte1 | byte2; - - return 3; -} - -/* - - untext - convert one ASCII character to byte - */ -static int /* number of result bytes, or error code */ -untext(src, dst, dstlen) -const char *src; /* known to be full length */ -char *dst; -size_t dstlen; /* not large enough is a failure */ -{ - if (dstlen < 1) - return SHORT; - - *dst = *src; - return 1; -} - -/* - - badch - produce a nice complaint about an unknown character - * - * If the compiler complains that the array bigenough[] has a negative - * size, that means the TTODATAV_BUF constant has been set too small. - */ -static const char * /* literal or errp */ -badch(src, errcode, errp, errlen) -const char *src; -int errcode; -char *errp; /* might be NULL */ -size_t errlen; -{ - static const char pre[] = "unknown character (`"; - static const char suf[] = "') in input"; - char buf[5]; -# define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf)) - struct sizecheck { - char bigenough[TTODATAV_BUF - REQD]; /* see above */ - }; - char ch; - - if (errp == NULL || errlen < REQD) - return "unknown character in input"; - strcpy(errp, pre); - ch = *(src + BADOFF(errcode)); - if (isprint(ch)) { - buf[0] = ch; - buf[1] = '\0'; - } else { - buf[0] = '\\'; - buf[1] = ((ch & 0700) >> 6) + '0'; - buf[2] = ((ch & 0070) >> 3) + '0'; - buf[3] = ((ch & 0007) >> 0) + '0'; - buf[4] = '\0'; - } - strcat(errp, buf); - strcat(errp, suf); - return (const char *)errp; -} - - - -#ifdef TTODATA_MAIN - -#include - -struct artab; -static void check(struct artab *r, char *buf, size_t n, err_t oops, int *status); -static void regress(char *pgm); -static void hexout(const char *s, size_t len, FILE *f); - -/* - - main - convert first argument to hex, or run regression - */ -int -main(int argc, char *argv[]) -{ - char buf[1024]; - char buf2[1024]; - char err[512]; - size_t n; - size_t i; - char *p = buf; - char *p2 = buf2; - char *pgm = argv[0]; - const char *oops; - - if (argc < 2) { - fprintf(stderr, "Usage: %s {0x|0s|-r}\n", pgm); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(pgm); /* should not return */ - fprintf(stderr, "%s: regress() returned?!?\n", pgm); - exit(1); - } - - oops = ttodatav(argv[1], 0, 0, buf, sizeof(buf), &n, - err, sizeof(err), TTODATAV_IGNORESPACE); - if (oops != NULL) { - fprintf(stderr, "%s: ttodata error `%s' in `%s'\n", pgm, - oops, argv[1]); - exit(1); - } - - if (n > sizeof(buf)) { - p = (char *)malloc((size_t)n); - if (p == NULL) { - fprintf(stderr, - "%s: unable to malloc %d bytes for result\n", - pgm, n); - exit(1); - } - oops = ttodata(argv[1], 0, 0, p, n, &n); - if (oops != NULL) { - fprintf(stderr, "%s: error `%s' in ttodata retry?!?\n", - pgm, oops); - exit(1); - } - } - - hexout(p, n, stdout); - printf("\n"); - - i = datatot(buf, n, 'h', buf2, sizeof(buf2)); - if (i == 0) { - fprintf(stderr, "%s: datatot reports error in `%s'\n", pgm, - argv[1]); - exit(1); - } - - if (i > sizeof(buf2)) { - p2 = (char *)malloc((size_t)i); - if (p == NULL) { - fprintf(stderr, - "%s: unable to malloc %d bytes for result\n", - pgm, i); - exit(1); - } - i = datatot(buf, n, 'h', p2, i); - if (i == 0) { - fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm); - exit(1); - } - } - - printf("%s\n", p2); - - exit(0); -} - -/* - - hexout - output an arbitrary-length string in hex - */ -static void -hexout(s, len, f) -const char *s; -size_t len; -FILE *f; -{ - size_t i; - - fprintf(f, "0x"); - for (i = 0; i < len; i++) - fprintf(f, "%02x", (unsigned char)s[i]); -} - -struct artab { - int base; -# define IGNORESPACE_BIAS 1000 - char *ascii; /* NULL for end */ - char *data; /* NULL for error expected */ -} atodatatab[] = { - { 0, "", NULL, }, - { 0, "0", NULL, }, - { 0, "0x", NULL, }, - { 0, "0xa", NULL, }, - { 0, "0xab", "\xab", }, - { 0, "0xabc", NULL, }, - { 0, "0xabcd", "\xab\xcd", }, - { 0, "0x0123456789", "\x01\x23\x45\x67\x89", }, - { 0, "0x01x", NULL, }, - { 0, "0xabcdef", "\xab\xcd\xef", }, - { 0, "0xABCDEF", "\xab\xcd\xef", }, - { 0, "0XaBc0eEd81f", "\xab\xc0\xee\xd8\x1f", }, - { 0, "0XaBc0_eEd8", "\xab\xc0\xee\xd8", }, - { 0, "0XaBc0_", NULL, }, - { 0, "0X_aBc0", NULL, }, - { 0, "0Xa_Bc0", NULL, }, - { 16, "aBc0eEd8", "\xab\xc0\xee\xd8", }, - { 0, "0s", NULL, }, - { 0, "0sA", NULL, }, - { 0, "0sBA", NULL, }, - { 0, "0sCBA", NULL, }, - { 0, "0sDCBA", "\x0c\x20\x40", }, - { 0, "0SDCBA", "\x0c\x20\x40", }, - { 0, "0sDA==", "\x0c", }, - { 0, "0sDC==", NULL, }, - { 0, "0sDCA=", "\x0c\x20", }, - { 0, "0sDCB=", NULL, }, - { 0, "0sDCAZ", "\x0c\x20\x19", }, - { 0, "0sDCAa", "\x0c\x20\x1a", }, - { 0, "0sDCAz", "\x0c\x20\x33", }, - { 0, "0sDCA0", "\x0c\x20\x34", }, - { 0, "0sDCA9", "\x0c\x20\x3d", }, - { 0, "0sDCA+", "\x0c\x20\x3e", }, - { 0, "0sDCA/", "\x0c\x20\x3f", }, - { 0, "0sAbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0s AbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sA braCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAb raCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbr aCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbra Cadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraC adabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCa dabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCad abra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCada bra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCadab ra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCadabr a+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCadabra +", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCadabra+ ", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { 0, "0t", NULL, }, - { 0, "0tabc_xyz", "abc_xyz", }, - { 256, "abc_xyz", "abc_xyz", }, - { 0, NULL, NULL, }, -}; - -struct drtab { - char *data; /* input; NULL for end */ - char format; - int buflen; /* -1 means big buffer */ - int outlen; /* -1 means strlen(ascii)+1 */ - char *ascii; /* NULL for error expected */ -} datatoatab[] = { - { "", 'x', -1, -1, NULL, }, - { "", 'X', -1, -1, NULL, }, - { "", 'n', -1, -1, NULL, }, - { "0", 'x', -1, -1, "0x30", }, - { "0", 'x', 0, 5, "---", }, - { "0", 'x', 1, 5, "", }, - { "0", 'x', 2, 5, "0", }, - { "0", 'x', 3, 5, "0x", }, - { "0", 'x', 4, 5, "0x3", }, - { "0", 'x', 5, 5, "0x30", }, - { "0", 'x', 6, 5, "0x30", }, - { "\xab\xcd", 'x', -1, -1, "0xabcd", }, - { "\x01\x23\x45\x67\x89", 'x', -1, -1, "0x0123456789", }, - { "\xab\xcd\xef", 'x', -1, -1, "0xabcdef", }, - { "\xab\xc0\xee\xd8\x1f", 'x', -1, -1, "0xabc0eed81f", }, - { "\x01\x02", 'h', -1, -1, "0x0102", }, - { "\x01\x02\x03\x04\x05\x06", 'h', -1, -1, "0x01020304_0506", }, - { "\xab\xc0\xee\xd8\x1f", 16, -1, -1, "abc0eed81f", }, - { "\x0c\x20\x40", 's', -1, -1, "0sDCBA", }, - { "\x0c\x20\x40", 's', 0, 7, "---", }, - { "\x0c\x20\x40", 's', 1, 7, "", }, - { "\x0c\x20\x40", 's', 2, 7, "0", }, - { "\x0c\x20\x40", 's', 3, 7, "0s", }, - { "\x0c\x20\x40", 's', 4, 7, "0sD", }, - { "\x0c\x20\x40", 's', 5, 7, "0sDC", }, - { "\x0c\x20\x40", 's', 6, 7, "0sDCB", }, - { "\x0c\x20\x40", 's', 7, 7, "0sDCBA", }, - { "\x0c\x20\x40", 's', 8, 7, "0sDCBA", }, - { "\x0c", 's', -1, -1, "0sDA==", }, - { "\x0c\x20", 's', -1, -1, "0sDCA=", }, - { "\x0c\x20\x19", 's', -1, -1, "0sDCAZ", }, - { "\x0c\x20\x1a", 's', -1, -1, "0sDCAa", }, - { "\x0c\x20\x33", 's', -1, -1, "0sDCAz", }, - { "\x0c\x20\x34", 's', -1, -1, "0sDCA0", }, - { "\x0c\x20\x3d", 's', -1, -1, "0sDCA9", }, - { "\x0c\x20\x3e", 's', -1, -1, "0sDCA+", }, - { "\x0c\x20\x3f", 's', -1, -1, "0sDCA/", }, - { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+", }, - { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+", }, - { NULL, 'x', -1, -1, NULL, }, -}; - -/* - - regress - regression-test ttodata() and datatot() - */ -static void -check(r, buf, n, oops, status) -struct artab *r; -char *buf; -size_t n; -err_t oops; -int *status; -{ - if (oops != NULL && r->data == NULL) - {} /* error expected */ - else if (oops != NULL) { - printf("`%s' gave error `%s', expecting %d `", r->ascii, - oops, strlen(r->data)); - hexout(r->data, strlen(r->data), stdout); - printf("'\n"); - *status = 1; - } else if (r->data == NULL) { - printf("`%s' gave %d `", r->ascii, n); - hexout(buf, n, stdout); - printf("', expecting error\n"); - *status = 1; - } else if (n != strlen(r->data)) { - printf("length wrong in `%s': got %d `", r->ascii, n); - hexout(buf, n, stdout); - printf("', expecting %d `", strlen(r->data)); - hexout(r->data, strlen(r->data), stdout); - printf("'\n"); - *status = 1; - } else if (memcmp(buf, r->data, n) != 0) { - printf("`%s' gave %d `", r->ascii, n); - hexout(buf, n, stdout); - printf("', expecting %d `", strlen(r->data)); - hexout(r->data, strlen(r->data), stdout); - printf("'\n"); - *status = 1; - } - fflush(stdout); -} - -static void /* should not return at all, in fact */ -regress(pgm) -char *pgm; -{ - struct artab *r; - struct drtab *dr; - char buf[100]; - size_t n; - int status = 0; - - for (r = atodatatab; r->ascii != NULL; r++) { - int base = r->base; - int xbase = 0; - - if ((base == 0 || base == IGNORESPACE_BIAS + 0) && r->ascii[0] == '0') { - switch (r->ascii[1]) { - case 'x': - case 'X': - xbase = 16; - break; - case 's': - case 'S': - xbase = 64; - break; - case 't': - case 'T': - xbase = 256; - break; - } - } - - if (base >= IGNORESPACE_BIAS) { - base = base - IGNORESPACE_BIAS; - check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status); - if (xbase != 0) - check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status); - } else { - check(r, buf, n, ttodata(r->ascii, 0, base, buf, sizeof(buf), &n), &status); - if (base == 64 || xbase == 64) - check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status); - if (xbase != 0) { - check(r, buf, n, ttodata(r->ascii+2, 0, xbase, buf, sizeof(buf), &n), &status); - if (base == 64 || xbase == 64) - check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status); - } - } - } - for (dr = datatoatab; dr->data != NULL; dr++) { - size_t should; - - strcpy(buf, "---"); - n = datatot(dr->data, strlen(dr->data), dr->format, buf, - (dr->buflen == -1) ? sizeof(buf) : dr->buflen); - should = (dr->ascii == NULL) ? 0 : strlen(dr->ascii) + 1; - if (dr->outlen != -1) - should = dr->outlen; - if (n == 0 && dr->ascii == NULL) - {} /* error expected */ - else if (n == 0) { - printf("`"); - hexout(dr->data, strlen(dr->data), stdout); - printf("' %c gave error, expecting %d `%s'\n", - dr->format, should, dr->ascii); - status = 1; - } else if (dr->ascii == NULL) { - printf("`"); - hexout(dr->data, strlen(dr->data), stdout); - printf("' %c gave %d `%.*s', expecting error\n", - dr->format, n, (int)n, buf); - status = 1; - } else if (n != should) { - printf("length wrong in `"); - hexout(dr->data, strlen(dr->data), stdout); - printf("': got %d `%s'", n, buf); - printf(", expecting %d `%s'\n", should, dr->ascii); - status = 1; - } else if (strcmp(buf, dr->ascii) != 0) { - printf("`"); - hexout(dr->data, strlen(dr->data), stdout); - printf("' gave %d `%s'", n, buf); - printf(", expecting %d `%s'\n", should, dr->ascii); - status = 1; - } - fflush(stdout); - } - exit(status); -} - -#endif /* TTODATA_MAIN */ diff --git a/src/libfreeswan/ttoprotoport.c b/src/libfreeswan/ttoprotoport.c deleted file mode 100644 index e75b206be..000000000 --- a/src/libfreeswan/ttoprotoport.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * conversion from protocol/port string to protocol and port - * Copyright (C) 2002 Mario Strasser , - * Zuercher Hochschule Winterthur, - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "internal.h" -#include "freeswan.h" - -/* - * ttoprotoport - converts from protocol/port string to protocol and port - */ -err_t -ttoprotoport(src, src_len, proto, port, has_port_wildcard) -char *src; /* input string */ -size_t src_len; /* length of input string, use strlen() if 0 */ -u_int8_t *proto; /* extracted protocol number */ -u_int16_t *port; /* extracted port number if it exists */ -bool *has_port_wildcard; /* set if port is %any */ -{ - char *end, *service_name; - char proto_name[16]; - int proto_len; - long int l; - struct protoent *protocol; - struct servent *service; - - /* get the length of the string */ - if (!src_len) src_len = strlen(src); - - /* locate delimiter '/' between protocol and port */ - end = strchr(src, '/'); - if (end != NULL) { - proto_len = end - src; - service_name = end + 1; - } else { - proto_len = src_len; - service_name = src + src_len; - } - - /* copy protocol name*/ - memset(proto_name, '\0', sizeof(proto_name)); - memcpy(proto_name, src, proto_len); - - /* extract protocol by trying to resolve it by name */ - protocol = getprotobyname(proto_name); - if (protocol != NULL) { - *proto = protocol->p_proto; - } - else /* failed, now try it by number */ - { - l = strtol(proto_name, &end, 0); - - if (*proto_name && *end) - return " is neither a number nor a valid name"; - - if (l < 0 || l > 0xff) - return " must be between 0 and 255"; - - *proto = (u_int8_t)l; - } - - /* is there a port wildcard? */ - *has_port_wildcard = (strcmp(service_name, "%any") == 0); - - if (*has_port_wildcard) - { - *port = 0; - return NULL; - } - - /* extract port by trying to resolve it by name */ - service = getservbyname(service_name, NULL); - if (service != NULL) { - *port = ntohs(service->s_port); - } - else /* failed, now try it by number */ - { - l = strtol(service_name, &end, 0); - - if (*service_name && *end) - return " is neither a number nor a valid name"; - - if (l < 0 || l > 0xffff) - return " must be between 0 and 65535"; - - *port = (u_int16_t)l; - } - return NULL; -} - diff --git a/src/libfreeswan/ttosa.3 b/src/libfreeswan/ttosa.3 deleted file mode 100644 index f9ea36a09..000000000 --- a/src/libfreeswan/ttosa.3 +++ /dev/null @@ -1,287 +0,0 @@ -.TH IPSEC_TTOSA 3 "26 Nov 2001" -.SH NAME -ipsec ttosa, satot \- convert IPsec Security Association IDs to and from text -.br -ipsec initsaid \- initialize an SA ID -.SH SYNOPSIS -.B "#include -.sp -.B "typedef struct {" -.ti +1c -.B "ip_address dst;" -.ti +1c -.B "ipsec_spi_t spi;" -.ti +1c -.B "int proto;" -.br -.B "} ip_said;" -.sp -.B "const char *ttosa(const char *src, size_t srclen," -.ti +1c -.B "ip_said *sa); -.br -.B "size_t satot(const ip_said *sa, int format," -.ti +1c -.B "char *dst, size_t dstlen);" -.br -.B "void initsaid(const ip_address *addr, ipsec_spi_t spi," -.ti +1c -.B "int proto, ip_said *dst);" -.SH DESCRIPTION -.I Ttosa -converts an ASCII Security Association (SA) specifier into an -.B ip_said -structure (containing -a destination-host address -in network byte order, -an SPI number in network byte order, and -a protocol code). -.I Satot -does the reverse conversion, back to a text SA specifier. -.I Initsaid -initializes an -.B ip_said -from separate items of information. -.PP -An SA is specified in text with a mail-like syntax, e.g. -.BR esp.5a7@1.2.3.4 . -An SA specifier contains -a protocol prefix (currently -.BR ah , -.BR esp , -.BR tun , -.BR comp , -or -.BR int ), -a single character indicating the address family -.RB ( . -for IPv4, -.B : -for IPv6), -an unsigned integer SPI number in hexadecimal (with no -.B 0x -prefix), -and an IP address. -The IP address can be any form accepted by -.IR ipsec_ttoaddr (3), -e.g. dotted-decimal IPv4 address, -colon-hex IPv6 address, -or DNS name. -.PP -As a special case, the SA specifier -.B %passthrough4 -or -.B %passthrough6 -signifies the special SA used to indicate that packets should be -passed through unaltered. -(At present, these are synonyms for -.B tun.0@0.0.0.0 -and -.B tun:0@:: -respectively, -but that is subject to change without notice.) -.B %passthrough -is a historical synonym for -.BR %passthrough4 . -These forms are known to both -.I ttosa -and -.IR satot , -so the internal representation is never visible. -.PP -Similarly, the SA specifiers -.BR %pass , -.BR %drop , -.BR %reject , -.BR %hold , -.BR %trap , -and -.BR %trapsubnet -signify special ``magic'' SAs used to indicate that packets should be -passed, dropped, rejected (dropped with ICMP notification), -held, -and trapped (sent up to -.IR ipsec_pluto (8), -with either of two forms of -.B %hold -automatically installed) -respectively. -These forms too are known to both routines, -so the internal representation of the magic SAs should never be visible. -.PP -The -.B -header file supplies the -.B ip_said -structure, as well as a data type -.B ipsec_spi_t -which is an unsigned 32-bit integer. -(There is no consistency between kernel and user on what such a type -is called, hence the header hides the differences.) -.PP -The protocol code uses the same numbers that IP does. -For user convenience, given the difficulty in acquiring the exact set of -protocol names used by the kernel, -.B -defines the names -.BR SA_ESP , -.BR SA_AH , -.BR SA_IPIP , -and -.BR SA_COMP -to have the same values as the kernel names -.BR IPPROTO_ESP , -.BR IPPROTO_AH , -.BR IPPROTO_IPIP , -and -.BR IPPROTO_COMP . -.PP -.B -also defines -.BR SA_INT -to have the value -.BR 61 -(reserved by IANA for ``any host internal protocol'') -and -.BR SPI_PASS , -.BR SPI_DROP , -.BR SPI_REJECT , -.BR SPI_HOLD , -and -.B SPI_TRAP -to have the values 256-260 (in \fIhost\fR byte order) respectively. -These are used in constructing the magic SAs -(which always have address -.BR 0.0.0.0 ). -.PP -If -.I satot -encounters an unknown protocol code, e.g. 77, -it yields output using a prefix -showing the code numerically, e.g. ``unk77''. -This form is -.I not -recognized by -.IR ttosa . -.PP -The -.I srclen -parameter of -.I ttosa -specifies the length of the string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I dstlen -parameter of -.I satot -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.B -header file defines a constant, -.BR SATOT_BUF , -which is the size of a buffer just large enough for worst-case results. -.PP -The -.I format -parameter of -.I satot -specifies what format is to be used for the conversion. -The value -.B 0 -(not the ASCII character -.BR '0' , -but a zero value) -specifies a reasonable default -(currently -lowercase protocol prefix, lowercase hexadecimal SPI, -dotted-decimal or colon-hex address). -The value -.B 'f' -is similar except that the SPI is padded with -.BR 0 s -to a fixed 32-bit width, to ease aligning displayed tables. -.PP -.I Ttosa -returns -.B NULL -for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.I Satot -returns -.B 0 -for a failure, and otherwise -always returns the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.PP -There is also, temporarily, support for some obsolete -forms of SA specifier which lack the address-family indicator. -.SH SEE ALSO -ipsec_ttoul(3), ipsec_ttoaddr(3), ipsec_samesaid(3), inet(3) -.SH DIAGNOSTICS -Fatal errors in -.I ttosa -are: -empty input; -input too small to be a legal SA specifier; -no -.B @ -in input; -unknown protocol prefix; -conversion error in -.I ttoul -or -.IR ttoaddr . -.PP -Fatal errors in -.I satot -are: -unknown format. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The restriction of text-to-binary error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The text-to-binary error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = ttosa( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/ttosa.c b/src/libfreeswan/ttosa.c deleted file mode 100644 index 9873231c0..000000000 --- a/src/libfreeswan/ttosa.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * convert from text form of SA ID to binary - * Copyright (C) 2000, 2001 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -static struct satype { - char *prefix; - size_t prelen; /* strlen(prefix) */ - int proto; -} satypes[] = { - { "ah", 2, SA_AH }, - { "esp", 3, SA_ESP }, - { "tun", 3, SA_IPIP }, - { "comp", 4, SA_COMP }, - { "int", 3, SA_INT }, - { NULL, 0, 0, } -}; - -static struct magic { - char *name; - char *really; -} magic[] = { - { PASSTHROUGHNAME, PASSTHROUGH4IS }, - { PASSTHROUGH4NAME, PASSTHROUGH4IS }, - { PASSTHROUGH6NAME, PASSTHROUGH6IS }, - { "%pass", "int256@0.0.0.0" }, - { "%drop", "int257@0.0.0.0" }, - { "%reject", "int258@0.0.0.0" }, - { "%hold", "int259@0.0.0.0" }, - { "%trap", "int260@0.0.0.0" }, - { "%trapsubnet", "int261@0.0.0.0" }, - { NULL, NULL } -}; - -/* - - ttosa - convert text "ah507@10.0.0.1" to SA identifier - */ -err_t /* NULL for success, else string literal */ -ttosa(src, srclen, sa) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -ip_said *sa; -{ - const char *at; - const char *addr; - size_t alen; - const char *spi = NULL; - struct satype *sat; - unsigned long ul; - const char *oops; - struct magic *mp; - size_t nlen; -# define MINLEN 5 /* ah0@0 is as short as it can get */ - int af; - int base; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - if (srclen < MINLEN) - return "string too short to be SA identifier"; - if (*src == '%') { - for (mp = magic; mp->name != NULL; mp++) { - nlen = strlen(mp->name); - if (srclen == nlen && memcmp(src, mp->name, nlen) == 0) - break; - } - if (mp->name == NULL) - return "unknown % keyword"; - src = mp->really; - srclen = strlen(src); - } - - at = memchr(src, '@', srclen); - if (at == NULL) - return "no @ in SA specifier"; - - for (sat = satypes; sat->prefix != NULL; sat++) - if (sat->prelen < srclen && - strncmp(src, sat->prefix, sat->prelen) == 0) { - sa->proto = sat->proto; - spi = src + sat->prelen; - break; /* NOTE BREAK OUT */ - } - if (sat->prefix == NULL) - return "SA specifier lacks valid protocol prefix"; - - if (spi >= at) - return "no SPI in SA specifier"; - switch (*spi) { - case '.': - af = AF_INET; - spi++; - base = 16; - break; - case ':': - af = AF_INET6; - spi++; - base = 16; - break; - default: - af = AF_UNSPEC; /* not known yet */ - base = 0; - break; - } - if (spi >= at) - return "no SPI found in SA specifier"; - oops = ttoul(spi, at - spi, base, &ul); - if (oops != NULL) - return oops; - sa->spi = htonl(ul); - - addr = at + 1; - alen = srclen - (addr - src); - if (af == AF_UNSPEC) - af = (memchr(addr, ':', alen) != NULL) ? AF_INET6 : AF_INET; - oops = ttoaddr(addr, alen, af, &sa->dst); - if (oops != NULL) - return oops; - - return NULL; -} - - - -#ifdef TTOSA_MAIN - -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - ip_said sa; - char buf[100]; - char buf2[100]; - const char *oops; - size_t n; - - if (argc < 2) { - fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - oops = ttosa(argv[1], 0, &sa); - if (oops != NULL) { - fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); - exit(1); - } - n = satot(&sa, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto); - fprintf(stderr, "%lx@", (long unsigned int)sa.spi); - (void) addrtot(&sa.dst, 0, buf2, sizeof(buf2)); - fprintf(stderr, "%s", buf2); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - int format; -# define FUDGE 0x1000 - char *input; - char *output; /* NULL means error expected */ -} rtab[] = { - {0, "esp257@1.2.3.0", "esp.101@1.2.3.0"}, - {0, "ah0x20@1.2.3.4", "ah.20@1.2.3.4"}, - {0, "tun20@1.2.3.4", "tun.14@1.2.3.4"}, - {0, "comp20@1.2.3.4", "comp.14@1.2.3.4"}, - {0, "esp257@::1", "esp:101@::1"}, - {0, "esp257@0bc:12de::1", "esp:101@bc:12de::1"}, - {0, "esp78@1049:1::8007:2040", "esp:4e@1049:1::8007:2040"}, - {0, "esp0x78@1049:1::8007:2040", "esp:78@1049:1::8007:2040"}, - {0, "ah78@1049:1::8007:2040", "ah:4e@1049:1::8007:2040"}, - {0, "ah0x78@1049:1::8007:2040", "ah:78@1049:1::8007:2040"}, - {0, "tun78@1049:1::8007:2040", "tun:4e@1049:1::8007:2040"}, - {0, "tun0x78@1049:1::8007:2040", "tun:78@1049:1::8007:2040"}, - {0, "duk99@3ffe:370:400:ff::9001:3001", NULL}, - {0, "esp78x@1049:1::8007:2040", NULL}, - {0, "esp0x78@1049:1:0xfff::8007:2040", NULL}, - {0, "es78@1049:1::8007:2040", NULL}, - {0, "", NULL}, - {0, "_", NULL}, - {0, "ah2.2", NULL}, - {0, "goo2@1.2.3.4", NULL}, - {0, "esp9@1.2.3.4", "esp.9@1.2.3.4"}, - {'f', "esp0xa9@1.2.3.4", "esp.000000a9@1.2.3.4"}, - {0, "espp9@1.2.3.4", NULL}, - {0, "es9@1.2.3.4", NULL}, - {0, "ah@1.2.3.4", NULL}, - {0, "esp7x7@1.2.3.4", NULL}, - {0, "esp77@1.0x2.3.4", NULL}, - {0, PASSTHROUGHNAME, PASSTHROUGH4NAME}, - {0, PASSTHROUGH6NAME, PASSTHROUGH6NAME}, - {0, "%pass", "%pass"}, - {0, "int256@0.0.0.0", "%pass"}, - {0, "%drop", "%drop"}, - {0, "int257@0.0.0.0", "%drop"}, - {0, "%reject", "%reject"}, - {0, "int258@0.0.0.0", "%reject"}, - {0, "%hold", "%hold"}, - {0, "int259@0.0.0.0", "%hold"}, - {0, "%trap", "%trap"}, - {0, "int260@0.0.0.0", "%trap"}, - {0, "%trapsubnet", "%trapsubnet"}, - {0, "int261@0.0.0.0", "%trapsubnet"}, - {0, "int262@0.0.0.0", "int.106@0.0.0.0"}, - {FUDGE, "esp9@1.2.3.4", "unk77.9@1.2.3.4"}, - {0, NULL, NULL} -}; - -void -regress(void) -{ - struct rtab *r; - int status = 0; - ip_said sa; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - - for (r = rtab; r->input != NULL; r++) { - strcpy(in, r->input); - oops = ttosa(in, 0, &sa); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s' ttosa failed: %s\n", r->input, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s' ttosa succeeded unexpectedly\n", - r->input); - status = 1; - } else { - if (r->format&FUDGE) - sa.proto = 77; - n = satot(&sa, (char)r->format, buf, sizeof(buf)); - if (n > sizeof(buf)) { - printf("`%s' satot failed: need %ld\n", - r->input, (long)n); - status = 1; - } else if (strcmp(r->output, buf) != 0) { - printf("`%s' gave `%s', expected `%s'\n", - r->input, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* TTOSA_MAIN */ diff --git a/src/libfreeswan/ttosubnet.c b/src/libfreeswan/ttosubnet.c deleted file mode 100644 index a18a3f326..000000000 --- a/src/libfreeswan/ttosubnet.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * convert from text form of subnet specification to binary - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -#ifndef DEFAULTSUBNET -#define DEFAULTSUBNET "%default" -#endif - -/* - - ttosubnet - convert text "addr/mask" to address and mask - * Mask can be integer bit count. - */ -err_t -ttosubnet(src, srclen, af, dst) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -int af; /* AF_INET or AF_INET6 */ -ip_subnet *dst; -{ - const char *slash; - const char *colon; - const char *mask; - size_t mlen; - const char *oops; - unsigned long bc; - static char def[] = DEFAULTSUBNET; -# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */ - static char defis4[] = "0/0"; -# define DEFIS4LEN (sizeof(defis4) - 1) - static char defis6[] = "::/0"; -# define DEFIS6LEN (sizeof(defis6) - 1) - ip_address addrtmp; - ip_address masktmp; - int nbits; - int i; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - switch (af) { - case AF_INET: - nbits = 32; - break; - case AF_INET6: - nbits = 128; - break; - default: - return "unknown address family in ttosubnet"; - break; - } - - if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) { - src = (af == AF_INET) ? defis4 : defis6; - srclen = (af == AF_INET) ? DEFIS4LEN : DEFIS6LEN; - } - - slash = memchr(src, '/', srclen); - if (slash == NULL) - return "no / in subnet specification"; - mask = slash + 1; - mlen = srclen - (mask - src); - - oops = ttoaddr(src, slash-src, af, &addrtmp); - if (oops != NULL) - return oops; - - /* extract port */ - colon = memchr(mask, ':', mlen); - if (colon == 0) - { - setportof(0, &addrtmp); - } - else - { - long port; - - oops = ttoul(colon+1, mlen-(colon-mask+1), 10, &port); - if (oops != NULL) - return oops; - setportof(htons(port), &addrtmp); - mlen = colon - mask; - } - - /*extract mask */ - oops = ttoul(mask, mlen, 10, &bc); - if (oops == NULL) { - /* ttoul succeeded, it's a bit-count mask */ - if (bc > nbits) - return "subnet mask bit count too large"; - i = bc; - } else { - oops = ttoaddr(mask, mlen, af, &masktmp); - if (oops != NULL) - return oops; - i = masktocount(&masktmp); - if (i < 0) - return "non-contiguous or otherwise erroneous mask"; - } - - return initsubnet(&addrtmp, i, '0', dst); -} - - - -#ifdef TTOSUBNET_MAIN - -#include - -void regress(void); - -int main(int argc, char *argv[]) -{ - ip_subnet s; - char buf[100]; - char buf2[100]; - const char *oops; - size_t n; - int af; - char *p; - - if (argc < 2) { - fprintf(stderr, "Usage: %s [-6] addr/mask\n", argv[0]); - fprintf(stderr, " or: %s -r\n", argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - af = AF_INET; - p = argv[1]; - if (strcmp(argv[1], "-6") == 0) { - af = AF_INET6; - p = argv[2]; - } else if (strchr(argv[1], ':') != NULL) - af = AF_INET6; - - oops = ttosubnet(p, 0, af, &s); - if (oops != NULL) { - fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); - exit(1); - } - n = subnettot(&s, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conversion of ", argv[0]); - (void) addrtot(&s.addr, 0, buf2, sizeof(buf2)); - fprintf(stderr, "%s/", buf2); - fprintf(stderr, "%d", s.maskbits); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - int family; - char *input; - char *output; /* NULL means error expected */ -} rtab[] = { - {4, "1.2.3.0/255.255.255.0", "1.2.3.0/24"}, - {4, "1.2.3.0/24", "1.2.3.0/24"}, - {4, "1.2.3.0/24:10", "1.2.3.0/24:10"}, - {4, "1.2.3.0/24:-1", NULL}, - {4, "1.2.3.0/24:none", NULL}, - {4, "1.2.3.0/24:", NULL}, - {4, "1.2.3.0/24:0x10", "1.2.3.0/24:16"}, - {4, "1.2.3.0/24:0X10", "1.2.3.0/24:16"}, - {4, "1.2.3.0/24:010", "1.2.3.0/24:8"}, - {4, "1.2.3.1/255.255.255.240", "1.2.3.0/28"}, - {4, "1.2.3.1/32", "1.2.3.1/32"}, - {4, "1.2.3.1/0", "0.0.0.0/0"}, -/* {4, "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0"}, */ - {4, "1.2.3.1/255.255.127.0", NULL}, - {4, "128.009.000.032/32", "128.9.0.32/32"}, - {4, "128.0x9.0.32/32", NULL}, - {4, "0x80090020/32", "128.9.0.32/32"}, - {4, "0x800x0020/32", NULL}, - {4, "128.9.0.32/0xffFF0000", "128.9.0.0/16"}, - {4, "128.9.0.32/0xff0000FF", NULL}, - {4, "128.9.0.32/0x0000ffFF", NULL}, - {4, "128.9.0.32/0x00ffFF0000", NULL}, - {4, "128.9.0.32/0xffFF", NULL}, - {4, "128.9.0.32.27/32", NULL}, - {4, "128.9.0k32/32", NULL}, - {4, "328.9.0.32/32", NULL}, - {4, "128.9..32/32", NULL}, - {4, "10/8", "10.0.0.0/8"}, - {4, "10.0/8", "10.0.0.0/8"}, - {4, "10.0.0/8", "10.0.0.0/8"}, - {4, "10.0.1/24", "10.0.1.0/24"}, - {4, "_", NULL}, - {4, "_/_", NULL}, - {4, "1.2.3.1", NULL}, - {4, "1.2.3.1/_", NULL}, - {4, "1.2.3.1/24._", NULL}, - {4, "1.2.3.1/99", NULL}, - {4, "localhost/32", "127.0.0.1/32"}, - {4, "%default", "0.0.0.0/0"}, - {6, "3049:1::8007:2040/0", "::/0"}, - {6, "3049:1::8007:2040/128", "3049:1::8007:2040/128"}, - {6, "3049:1::192.168.0.1/128", NULL}, /*"3049:1::c0a8:1/128",*/ - {6, "3049:1::8007::2040/128", NULL}, - {6, "3049:1::8007:2040/ffff::0", "3049::/16"}, - {6, "3049:1::8007:2040/64", "3049:1::/64"}, - {6, "3049:1::8007:2040/ffff::", "3049::/16"}, - {6, "3049:1::8007:2040/0000:ffff::0", NULL}, - {6, "3049:1::8007:2040/ff1f::0", NULL}, - {6, "3049:1::8007:x:2040/128", NULL}, - {6, "3049:1t::8007:2040/128", NULL}, - {6, "3049:1::80071:2040/128", NULL}, - {6, "::/21", "::/21"}, - {6, "::1/128", "::1/128"}, - {6, "1::/21", "1::/21"}, - {6, "1::2/128", "1::2/128"}, - {6, "1:0:0:0:0:0:0:2/128", "1::2/128"}, - {6, "1:0:0:0:3:0:0:2/128", "1::3:0:0:2/128"}, - {6, "1:0:0:3:0:0:0:2/128", "1::3:0:0:0:2/128"}, - {6, "1:0:3:0:0:0:0:2/128", "1:0:3::2/128"}, - {6, "abcd:ef01:2345:6789:0:00a:000:20/128", "abcd:ef01:2345:6789:0:a:0:20/128"}, - {6, "3049:1::8007:2040/ffff:ffff:", NULL}, - {6, "3049:1::8007:2040/ffff:88::", NULL}, - {6, "3049:12::9000:3200/ffff:fff0::", "3049:10::/28"}, - {6, "3049:12::9000:3200/28", "3049:10::/28"}, - {6, "3049:12::9000:3200/ff00:::", NULL}, - {6, "3049:12::9000:3200/ffff:::", NULL}, - {6, "3049:12::9000:3200/128_", NULL}, - {6, "3049:12::9000:3200/", NULL}, - {6, "%default", "::/0"}, - {4, NULL, NULL} -}; - -void -regress(void) -{ - struct rtab *r; - int status = 0; - ip_subnet s; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - int af; - - for (r = rtab; r->input != NULL; r++) { - af = (r->family == 4) ? AF_INET : AF_INET6; - strcpy(in, r->input); - oops = ttosubnet(in, 0, af, &s); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s' ttosubnet failed: %s\n", r->input, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s' ttosubnet succeeded unexpectedly\n", - r->input); - status = 1; - } else { - n = subnettot(&s, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - printf("`%s' subnettot failed: need %ld\n", - r->input, (long)n); - status = 1; - } else if (strcmp(r->output, buf) != 0) { - printf("`%s' gave `%s', expected `%s'\n", - r->input, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* TTOSUBNET_MAIN */ diff --git a/src/libfreeswan/ttoul.3 b/src/libfreeswan/ttoul.3 deleted file mode 100644 index ffd9fb38a..000000000 --- a/src/libfreeswan/ttoul.3 +++ /dev/null @@ -1,191 +0,0 @@ -.TH IPSEC_TTOUL 3 "16 Aug 2000" -.SH NAME -ipsec ttoul, ultot \- convert unsigned-long numbers to and from text -.SH SYNOPSIS -.B "#include -.sp -.B "const char *ttoul(const char *src, size_t srclen," -.ti +1c -.B "int base, unsigned long *n);" -.br -.B "size_t ultot(unsigned long n, int format, char *dst," -.ti +1c -.B "size_t dstlen);" -.SH DESCRIPTION -.I Ttoul -converts a text-string number into a binary -.B "unsigned long" -value. -.I Ultot -does the reverse conversion, back to a text version. -.PP -Numbers are specified in text as -decimal (e.g. -.BR 123 ), -octal with a leading zero (e.g. -.BR 012 , -which has value 10), -or hexadecimal with a leading -.B 0x -(e.g. -.BR 0x1f , -which has value 31) -in either upper or lower case. -.PP -The -.I srclen -parameter of -.I ttoul -specifies the length of the string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I base -parameter of -.I ttoul -can be -.BR 8 , -.BR 10 , -or -.BR 16 , -in which case the number supplied is assumed to be of that form -(and in the case of -.BR 16 , -to lack any -.B 0x -prefix). -It can also be -.BR 0 , -in which case the number is examined for a leading zero -or a leading -.B 0x -to determine its base. -.PP -The -.I dstlen -parameter of -.I ultot -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.I freeswan.h -header file defines a constant, -.BR ULTOT_BUF , -which is the size of a buffer just large enough for worst-case results. -.PP -The -.I format -parameter of -.I ultot -must be one of: -.RS -.IP \fB'o'\fR 4 -octal conversion with leading -.B 0 -.IP \fB\ 8\fR -octal conversion with no leading -.B 0 -.IP \fB'd'\fR -decimal conversion -.IP \fB10\fR -same as -.B d -.IP \fB'x'\fR -hexadecimal conversion, including leading -.B 0x -.IP \fB16\fR -hexadecimal conversion with no leading -.B 0x -.IP \fB17\fR -like -.B 16 -except padded on left with -.BR 0 s -to eight digits (full width of a 32-bit number) -.RE -.PP -.I Ttoul -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.I Ultot -returns -.B 0 -for a failure, and otherwise -returns the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL -(it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred). -.SH SEE ALSO -atol(3), strtoul(3) -.SH DIAGNOSTICS -Fatal errors in -.I ttoul -are: -empty input; -unknown -.IR base ; -non-digit character found; -number too large for an -.BR "unsigned long" . -.PP -Fatal errors in -.I ultot -are: -unknown -.IR format . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -Conversion of -.B 0 -with format -.B o -yields -.BR 00 . -.PP -.I Ultot -format -.B 17 -is a bit of a kludge. -.PP -The restriction of error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The error-reporting convention lends itself to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = ttoul( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/ttoul.c b/src/libfreeswan/ttoul.c deleted file mode 100644 index 7524789c4..000000000 --- a/src/libfreeswan/ttoul.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * convert from text form of unsigned long to binary - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - ttoul - convert text substring to unsigned long number - */ -const char * /* NULL for success, else string literal */ -ttoul(src, srclen, base, resultp) -const char *src; -size_t srclen; /* 0 means strlen(src) */ -int base; /* 0 means figure it out */ -unsigned long *resultp; -{ - const char *stop; - static char hex[] = "0123456789abcdef"; - static char uchex[] = "0123456789ABCDEF"; - int d; - char c; - char *p; - unsigned long r; - unsigned long rlimit; - int dlimit; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - if (base == 0) { - if (srclen > 2 && *src == '0' && - (*(src+1) == 'x' || *(src+1) == 'X')) - return ttoul(src+2, srclen-2, 16, resultp); - if (srclen > 1 && *src == '0') - return ttoul(src+1, srclen-1, 8, resultp); - return ttoul(src, srclen, 10, resultp); - } - if (base != 8 && base != 10 && base != 16) - return "unsupported number base"; - - r = 0; - stop = src + srclen; - if (base == 16) { - while (src < stop) { - c = *src++; - p = strchr(hex, c); - if (p != NULL) - d = p - hex; - else { - p = strchr(uchex, c); - if (p == NULL) - return "non-hex digit in hex number"; - d = p - uchex; - } - r = (r << 4) | d; - } - /* defer length check to catch invalid digits first */ - if (srclen > sizeof(unsigned long) * 2) - return "hex number too long"; - } else { - rlimit = ULONG_MAX / base; - dlimit = (int)(ULONG_MAX - rlimit*base); - while (src < stop) { - c = *src++; - d = c - '0'; - if (d < 0 || d >= base) - return "non-digit in number"; - if (r > rlimit || (r == rlimit && d > dlimit)) - return "unsigned-long overflow"; - r = r*base + d; - } - } - - *resultp = r; - return NULL; -} diff --git a/src/libfreeswan/ultoa.c b/src/libfreeswan/ultoa.c deleted file mode 100644 index 16ddd2c1e..000000000 --- a/src/libfreeswan/ultoa.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * convert unsigned long to ASCII - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - ultoa - convert unsigned long to decimal ASCII - */ -size_t /* length required for full conversion */ -ultoa(n, base, dst, dstlen) -unsigned long n; -int base; -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - char buf[3*sizeof(unsigned long) + 1]; - char *bufend = buf + sizeof(buf); - size_t len; - char *p; - static char hex[] = "0123456789abcdef"; - - p = bufend; - *--p = '\0'; - if (base == 10) { - do { - *--p = n%10 + '0'; - n /= 10; - } while (n != 0); - } else if (base == 16) { - do { - *--p = hex[n&0xf]; - n >>= 4; - } while (n != 0); - *--p = 'x'; - *--p = '0'; - } else if (base == 8) { - do { - *--p = (n&07) + '0'; - n >>= 3; - } while (n != 0); - *--p = '0'; - } else - *--p = '?'; - - len = bufend - p; - - if (dstlen > 0) { - if (len > dstlen) - *(p + dstlen - 1) = '\0'; - strcpy(dst, p); - } - return len; -} diff --git a/src/libfreeswan/ultot.c b/src/libfreeswan/ultot.c deleted file mode 100644 index 6685f8f7c..000000000 --- a/src/libfreeswan/ultot.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * convert unsigned long to text - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - ultot - convert unsigned long to text - */ -size_t /* length required for full conversion */ -ultot(n, base, dst, dstlen) -unsigned long n; -int base; -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - char buf[3*sizeof(unsigned long) + 1]; - char *bufend = buf + sizeof(buf); - size_t len; - char *p; - static char hex[] = "0123456789abcdef"; -# define HEX32 (32/4) - - p = bufend; - *--p = '\0'; - switch (base) { - case 10: - case 'd': - do { - *--p = n%10 + '0'; - n /= 10; - } while (n != 0); - break; - case 16: - case 17: - case 'x': - do { - *--p = hex[n&0xf]; - n >>= 4; - } while (n != 0); - if (base == 17) - while (bufend - p < HEX32 + 1) - *--p = '0'; - if (base == 'x') { - *--p = 'x'; - *--p = '0'; - } - break; - case 8: - case 'o': - do { - *--p = (n&07) + '0'; - n >>= 3; - } while (n != 0); - if (base == 'o') - *--p = '0'; - break; - default: - return 0; - break; - } - - len = bufend - p; - if (dstlen > 0) { - if (len > dstlen) - *(p + dstlen - 1) = '\0'; - strcpy(dst, p); - } - return len; -} diff --git a/src/pluto/.gitignore b/src/pluto/.gitignore deleted file mode 100644 index 8aa8745ed..000000000 --- a/src/pluto/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -pluto -_pluto_adns diff --git a/src/pluto/Android.mk b/src/pluto/Android.mk deleted file mode 100644 index 618f79c42..000000000 --- a/src/pluto/Android.mk +++ /dev/null @@ -1,80 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# copy-n-paste from Makefile.am -LOCAL_SRC_FILES := \ -ac.c ac.h \ -alg_info.c alg_info.h \ -ca.c ca.h \ -certs.c certs.h \ -connections.c connections.h \ -constants.c constants.h \ -cookie.c cookie.h \ -crl.c crl.h \ -crypto.c crypto.h \ -db_ops.c db_ops.h \ -defs.c defs.h \ -demux.c demux.h \ -event_queue.c event_queue.h \ -fetch.c fetch.h \ -foodgroups.c foodgroups.h \ -ike_alg.c ike_alg.h \ -ipsec_doi.c ipsec_doi.h \ -kameipsec.h \ -kernel.c kernel.h \ -kernel_alg.c kernel_alg.h \ -kernel_pfkey.c kernel_pfkey.h \ -keys.c keys.h \ -lex.c lex.h \ -log.c log.h \ -myid.c myid.h \ -modecfg.c modecfg.h \ -nat_traversal.c nat_traversal.h \ -ocsp.c ocsp.h \ -packet.c packet.h \ -pkcs7.c pkcs7.h \ -plugin_list.c plugin_list.h \ -pluto.c pluto.h \ -plutomain.c \ -rcv_whack.c rcv_whack.h \ -server.c server.h \ -smartcard.c smartcard.h \ -spdb.c spdb.h \ -state.c state.h \ -timer.c timer.h \ -vendor.c vendor.h \ -virtual.c virtual.h \ -whack_attribute.c whack_attribute.h \ -xauth/xauth_manager.c xauth/xauth_manager.h \ -xauth/xauth_provider.h xauth/xauth_verifier.h \ -x509.c x509.h \ -builder.c builder.h \ -rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h - -LOCAL_SRC_FILES += $(call add_plugin, xauth) - -# build pluto ------------------------------------------------------------------ - -LOCAL_C_INCLUDES += \ - $(libvstr_PATH) \ - $(strongswan_PATH)/src/libhydra \ - $(strongswan_PATH)/src/libstrongswan \ - $(strongswan_PATH)/src/libfreeswan \ - $(strongswan_PATH)/src/whack - -LOCAL_CFLAGS := $(strongswan_CFLAGS) \ - -DPLUTO -DVENDORID -DXAUTH_VID -DCISCO_QUIRKS \ - -DTHREADS -DKERNEL26_HAS_KAME_DUPLICATES \ - -DPLUGINS='"$(strongswan_PLUTO_PLUGINS)"' - -LOCAL_MODULE := pluto - -LOCAL_MODULE_TAGS := optional - -LOCAL_ARM_MODE := arm - -LOCAL_PRELINK_MODULE := false - -LOCAL_SHARED_LIBRARIES += libstrongswan libhydra libfreeswan libcutils - -include $(BUILD_EXECUTABLE) diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am deleted file mode 100644 index 3fd0e039c..000000000 --- a/src/pluto/Makefile.am +++ /dev/null @@ -1,155 +0,0 @@ -# Makefile.am was ported from the old Makefile the most -# painless way. Only the most important options are included, -# further work may be necessary here... - -ipsec_PROGRAMS = pluto - -if USE_ADNS -ipsec_PROGRAMS += _pluto_adns -endif - -pluto_SOURCES = \ -ac.c ac.h \ -alg_info.c alg_info.h \ -ca.c ca.h \ -certs.c certs.h \ -connections.c connections.h \ -constants.c constants.h \ -cookie.c cookie.h \ -crl.c crl.h \ -crypto.c crypto.h \ -db_ops.c db_ops.h \ -defs.c defs.h \ -demux.c demux.h \ -event_queue.c event_queue.h \ -fetch.c fetch.h \ -foodgroups.c foodgroups.h \ -ike_alg.c ike_alg.h \ -ipsec_doi.c ipsec_doi.h \ -kameipsec.h \ -kernel.c kernel.h \ -kernel_alg.c kernel_alg.h \ -kernel_pfkey.c kernel_pfkey.h \ -keys.c keys.h \ -lex.c lex.h \ -log.c log.h \ -myid.c myid.h \ -modecfg.c modecfg.h \ -nat_traversal.c nat_traversal.h \ -ocsp.c ocsp.h \ -packet.c packet.h \ -pkcs7.c pkcs7.h \ -plugin_list.c plugin_list.h \ -pluto.c pluto.h \ -plutomain.c \ -rcv_whack.c rcv_whack.h \ -server.c server.h \ -smartcard.c smartcard.h \ -spdb.c spdb.h \ -state.c state.h \ -timer.c timer.h \ -vendor.c vendor.h \ -virtual.c virtual.h \ -whack_attribute.c whack_attribute.h \ -xauth/xauth_manager.c xauth/xauth_manager.h \ -xauth/xauth_provider.h xauth/xauth_verifier.h \ -x509.c x509.h \ -builder.c builder.h \ -rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h - -if USE_ADNS -pluto_SOURCES += \ -dnskey.c dnskey.h - -_pluto_adns_SOURCES = \ -adns.c adns.h -endif - -plutomain.o : $(top_builddir)/config.status - -LIBSTRONGSWANDIR=$(top_builddir)/src/libstrongswan -LIBFREESWANDIR=$(top_builddir)/src/libfreeswan -LIBHYDRADIR=$(top_builddir)/src/libhydra - -INCLUDES = \ --I${linux_headers} \ --I$(top_srcdir)/src/libstrongswan \ --I$(top_srcdir)/src/libfreeswan \ --I$(top_srcdir)/src/libhydra \ --I$(top_srcdir)/src/whack - -AM_CFLAGS = -rdynamic \ --DIPSEC_DIR=\"${ipsecdir}\" \ --DIPSEC_CONFDIR=\"${sysconfdir}\" \ --DIPSEC_PIDDIR=\"${piddir}\" \ --DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ --DPLUGINS=\""${pluto_plugins}\"" \ --DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" \ --DKERNEL26_HAS_KAME_DUPLICATES \ --DPLUTO -DDEBUG - -pluto_LDADD = \ -$(LIBSTRONGSWANDIR)/libstrongswan.la \ -$(LIBFREESWANDIR)/libfreeswan.a \ -$(LIBHYDRADIR)/libhydra.la \ --lresolv $(PTHREADLIB) $(DLLIB) - -if USE_ADNS -_pluto_adns_LDADD = \ -$(LIBFREESWANDIR)/libfreeswan.a \ --lresolv $(DLLIB) -endif - -dist_man_MANS = pluto.8 - -EXTRA_DIST = Android.mk - -# compile options -################# - -# This compile option activates the sending of a strongSwan VID -if USE_VENDORID - AM_CFLAGS += -DVENDORID -endif - -# This compile option activates the sending of the XAUTH VID -if USE_XAUTH_VID - AM_CFLAGS += -DXAUTH_VID -endif - -# This compile option activates the support of the Cisco VPN client -if USE_CISCO_QUIRKS - AM_CFLAGS += -DCISCO_QUIRKS -endif - -# This compile option activates NAT traversal with IPSec transport mode -if USE_NAT_TRANSPORT - AM_CFLAGS += -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT -endif - -# This compile option activates smartcard support -if USE_SMARTCARD - AM_CFLAGS += -DSMARTCARD -endif - -if USE_LIBCAP - pluto_LDADD += -lcap -endif - -if USE_THREADS - AM_CFLAGS += -DTHREADS -endif - -if USE_ADNS - AM_CFLAGS += -DADNS -endif - -# build optional plugins -######################## - -SUBDIRS = . - -if USE_XAUTH - SUBDIRS += plugins/xauth -endif - diff --git a/src/pluto/ac.c b/src/pluto/ac.c deleted file mode 100644 index cd8007aea..000000000 --- a/src/pluto/ac.c +++ /dev/null @@ -1,298 +0,0 @@ -/* Support of X.509 attribute certificates - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2009 Andreas Steffen - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include -#include -#include -#include - -#include "ac.h" -#include "ca.h" -#include "certs.h" -#include "fetch.h" -#include "log.h" - -/** - * Chained list of X.509 attribute certificates - */ -static linked_list_t *acerts = NULL; - -/** - * Initialize the linked list of attribute certificates - */ -void ac_initialize(void) -{ - acerts = linked_list_create(); -} - -/** - * Free the linked list of attribute certificates - */ -void ac_finalize(void) -{ - if (acerts) - { - acerts->destroy_offset(acerts, offsetof(certificate_t, destroy)); - } -} - -/** - * Get a X.509 attribute certificate for a given holder - */ -certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial) -{ - enumerator_t *enumerator; - certificate_t *cert, *found = NULL; - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert)) - { - ac_t *ac = (ac_t*)cert; - - if (issuer->equals(issuer, ac->get_holderIssuer(ac)) && - chunk_equals(serial, ac->get_holderSerial(ac))) - { - found = cert; - break; - } - } - enumerator->destroy(enumerator); - return found; -} - -/** - * Verifies a X.509 attribute certificate - */ -bool ac_verify_cert(certificate_t *cert, bool strict) -{ - ac_t *ac = (ac_t*)cert; - identification_t *subject = cert->get_subject(cert); - identification_t *issuer = cert->get_issuer(cert); - chunk_t authKeyID = ac->get_authKeyIdentifier(ac); - cert_t *aacert; - time_t notBefore, valid_until; - - DBG1(DBG_LIB, "holder: '%Y'", subject); - DBG1(DBG_LIB, "issuer: '%Y'", issuer); - - if (!cert->get_validity(cert, NULL, NULL, &valid_until)) - { - DBG1(DBG_LIB, "attribute certificate is invalid (valid from %T to %T)", - ¬Before, FALSE, &valid_until, FALSE); - return FALSE; - } - DBG1(DBG_LIB, "attribute certificate is valid until %T", &valid_until, - FALSE); - - lock_authcert_list("verify_x509acert"); - aacert = get_authcert(issuer, authKeyID, X509_AA); - unlock_authcert_list("verify_x509acert"); - - if (aacert == NULL) - { - DBG1(DBG_LIB, "issuer aacert not found"); - return FALSE; - } - DBG2(DBG_LIB, "issuer aacert found"); - - if (!cert->issued_by(cert, aacert->cert)) - { - DBG1(DBG_LIB, "attribute certificate signature is invalid"); - return FALSE; - } - DBG1(DBG_LIB, "attribute certificate signature is valid"); - - return verify_x509cert(aacert, strict, &valid_until); -} - -/** - * Add a X.509 attribute certificate to the chained list - */ -static void ac_add_cert(certificate_t *cert) -{ - ac_t *ac = (ac_t*)cert; - identification_t *hIssuer = ac->get_holderIssuer(ac); - chunk_t hSerial = ac->get_holderSerial(ac); - - enumerator_t *enumerator; - certificate_t *cert_old; - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert_old)) - { - ac_t *ac_old = (ac_t*)cert_old; - - if (hIssuer->equals(hIssuer, ac_old->get_holderIssuer(ac_old)) && - chunk_equals(hSerial, ac_old->get_holderSerial(ac_old))) - { - if (certificate_is_newer(cert, cert_old)) - { - acerts->remove_at(acerts, enumerator); - cert_old->destroy(cert_old); - } - else - { - cert->destroy(cert); - cert = NULL; - } - break; - } - } - enumerator->destroy(enumerator); - - if (cert) - { - acerts->insert_last(acerts, cert); - } -} - -/** - * Check if at least one peer attribute matches a connection attribute - */ -bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn, - ietf_attributes_t *conn_attributes) -{ - bool match; - - if (conn_attributes == NULL) - { - return TRUE; - } - - match = conn_attributes->matches(conn_attributes, peer_attributes); - DBG1(DBG_LIB, "%s: peer with attributes '%s' is %sa member of the " - "groups '%s'", conn, peer_attributes->get_string(peer_attributes), - match ? "" : "not ", conn_attributes->get_string(conn_attributes)); - - return match; -} - -/** - * Loads X.509 attribute certificates - */ -void ac_load_certs(void) -{ - enumerator_t *enumerator; - struct stat st; - char *file; - - DBG1(DBG_LIB, "loading attribute certificates from '%s'", A_CERT_PATH); - - enumerator = enumerator_create_directory(A_CERT_PATH); - if (!enumerator) - { - return; - } - - while (enumerator->enumerate(enumerator, NULL, &file, &st)) - { - certificate_t *cert; - - if (!S_ISREG(st.st_mode)) - { - /* skip special file */ - continue; - } - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, - BUILD_FROM_FILE, file, BUILD_END); - if (cert) - { - DBG1(DBG_LIB, " loaded attribute certificate from '%s'", file); - ac_add_cert(cert); - } - } - enumerator->destroy(enumerator); -} - -/** - * List all X.509 attribute certificates in the chained list - */ -void ac_list_certs(bool utc) -{ - enumerator_t *enumerator; - certificate_t *cert; - time_t now; - - /* determine the current time */ - time(&now); - - if (acerts->get_count(acerts) > 0) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:"); - } - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert)) - { - ac_t *ac = (ac_t*)cert; - identification_t *entityName, *holderIssuer, *issuer; - chunk_t holderSerial, serial, authKeyID; - time_t notBefore, notAfter; - ietf_attributes_t *groups; - - whack_log(RC_COMMENT, " "); - - entityName = cert->get_subject(cert); - if (entityName) - { - whack_log(RC_COMMENT, " holder: \"%Y\"", entityName); - } - - holderIssuer = ac->get_holderIssuer(ac); - if (holderIssuer) - { - whack_log(RC_COMMENT, " hissuer: \"%Y\"", holderIssuer); - } - - holderSerial = chunk_skip_zero(ac->get_holderSerial(ac)); - if (holderSerial.ptr) - { - whack_log(RC_COMMENT, " hserial: %#B", &holderSerial); - } - - groups = ac->get_groups(ac); - if (groups) - { - whack_log(RC_COMMENT, " groups: %s", groups->get_string(groups)); - groups->destroy(groups); - } - - issuer = cert->get_issuer(cert); - whack_log(RC_COMMENT, " issuer: \"%Y\"", issuer); - - serial = chunk_skip_zero(ac->get_serial(ac)); - whack_log(RC_COMMENT, " serial: %#B", &serial); - - cert->get_validity(cert, &now, ¬Before, ¬After); - whack_log(RC_COMMENT, " validity: not before %T %s", - ¬Before, utc, - (notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %T %s", ¬After, utc, - check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE)); - - authKeyID = ac->get_authKeyIdentifier(ac); - if (authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); - } - } - enumerator->destroy(enumerator); -} - diff --git a/src/pluto/ac.h b/src/pluto/ac.h deleted file mode 100644 index d4e0c1590..000000000 --- a/src/pluto/ac.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Support of X.509 attribute certificates - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2009 Andreas Steffen - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _AC_H -#define _AC_H - -#include -#include -#include - -/* access structure for an X.509 attribute certificate */ - -extern void ac_initialize(void); -extern void ac_finalize(void); -extern void ac_load_certs(void); -extern void ac_list_certs(bool utc); - -extern certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial); - -extern bool ac_verify_cert(certificate_t *ac, bool strict); - -extern bool match_group_membership(ietf_attributes_t *peer_attributes, - char *conn, - ietf_attributes_t *conn_attributes); - -#endif /* _AC_H */ diff --git a/src/pluto/adns.c b/src/pluto/adns.c deleted file mode 100644 index 76b459216..000000000 --- a/src/pluto/adns.c +++ /dev/null @@ -1,610 +0,0 @@ -/* Pluto Asynchronous DNS Helper Program -- for internal use only! - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* This program executes as multiple processes. The Master process - * receives queries (struct adns_query messages) from Pluto and distributes - * them amongst Worker processes. These Worker processes are created - * by the Master whenever a query arrives and no existing Worker is free. - * At most MAX_WORKERS will be created; after that, the Master will queue - * queries until a Worker becomes free. When a Worker has an answer from - * the resolver, it sends the answer as a struct adns_answer message to the - * Master. The Master then forwards the answer to Pluto, noting that - * the Worker is free to accept another query. - * - * The protocol is simple: Pluto sends a sequence of queries and receives - * a sequence of answers. select(2) is used by Pluto and by the Master - * process to decide when to read, but writes are done without checking - * for readiness. Communications is via pipes. Since only one process - * can write to each pipe, messages will not be interleaved. Fixed length - * records are used for simplicity. - * - * Pluto needs a way to indicate to the Master when to shut down - * and the Master needs to indicate this to each worker. EOF on the pipe - * signifies this. - * - * The interfaces between these components are considered private to - * Pluto. This allows us to get away with less checking. This is a - * reason to use pipes instead of TCP/IP. - * - * Although the code uses plain old UNIX processes, it could be modified - * to use threads. That might reduce resource requirements. It would - * preclude running on systems without thread-safe resolvers. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* ??? for h_errno */ - -#include - -/* GCC magic! */ -#ifdef GCC_LINT -# define UNUSED __attribute__ ((unused)) -#else -# define UNUSED /* ignore */ -#endif - -#include "constants.h" -#include "adns.h" /* needs */ - -/* shared by all processes */ - -static const char *name; /* program name, for messages */ - -static bool debug = FALSE; - -/* Read a variable-length record from a pipe (and no more!). - * First bytes must be a size_t containing the length. - * HES_CONTINUE if record read - * HES_OK if EOF - * HES_IO_ERROR_IN if errno tells the tale. - * Others are errors. - */ -static enum helper_exit_status -read_pipe(int fd, unsigned char *stuff, size_t minlen, size_t maxlen) -{ - size_t n = 0; - size_t goal = minlen; - - do { - ssize_t m = read(fd, stuff + n, goal - n); - - if (m == -1) - { - if (errno != EINTR) - { - syslog(LOG_ERR, "Input error on pipe: %s", strerror(errno)); - return HES_IO_ERROR_IN; - } - } - else if (m == 0) - { - return HES_OK; /* treat empty message as EOF */ - } - else - { - n += m; - if (n >= sizeof(size_t)) - { - goal = *(size_t *)(void *)stuff; - if (goal < minlen || maxlen < goal) - { - if (debug) - fprintf(stderr, "%lu : [%lu, %lu]\n" - , (unsigned long)goal - , (unsigned long)minlen, (unsigned long)maxlen); - return HES_BAD_LEN; - } - } - } - } while (n < goal); - - return HES_CONTINUE; -} - -/* Write a variable-length record to a pipe. - * First bytes must be a size_t containing the length. - * HES_CONTINUE if record written - * Others are errors. - */ -static enum helper_exit_status -write_pipe(int fd, const unsigned char *stuff) -{ - size_t len = *(const size_t *)(const void *)stuff; - size_t n = 0; - - do { - ssize_t m = write(fd, stuff + n, len - n); - - if (m == -1) - { - /* error, but ignore and retry if EINTR */ - if (errno != EINTR) - { - syslog(LOG_ERR, "Output error from master: %s", strerror(errno)); - return HES_IO_ERROR_OUT; - } - } - else - { - n += m; - } - } while (n != len); - return HES_CONTINUE; -} - -/**************** worker process ****************/ - -/* The interface in RHL6.x and BIND distribution 8.2.2 are different, - * so we build some of our own :-( - */ - -/* Support deprecated interface to allow for older releases of the resolver. - * Fake new interface! - * See resolver(3) bind distribution (should be in RHL6.1, but isn't). - * __RES was 19960801 in RHL6.2, an old resolver. - */ - -#if (__RES) <= 19960801 -# define OLD_RESOLVER 1 -#endif - -#ifdef OLD_RESOLVER - -# define res_ninit(statp) res_init() -# define res_nquery(statp, dname, class, type, answer, anslen) \ - res_query(dname, class, type, answer, anslen) -# define res_nclose(statp) res_close() - -static struct __res_state *statp = &_res; - -#else /* !OLD_RESOLVER */ - -static struct __res_state my_res_state /* = { 0 } */; -static res_state statp = &my_res_state; - -#endif /* !OLD_RESOLVER */ - -static int -worker(int qfd, int afd) -{ - { - int r = res_ninit(statp); - - if (r != 0) - { - syslog(LOG_ERR, "cannot initialize resolver"); - return HES_RES_INIT; - } -#ifndef OLD_RESOLVER - statp->options |= RES_ROTATE; -#endif - statp->options |= RES_DEBUG; - } - - for (;;) - { - struct adns_query q; - struct adns_answer a; - - enum helper_exit_status r = read_pipe(qfd, (unsigned char *)&q - , sizeof(q), sizeof(q)); - - if (r != HES_CONTINUE) - return r; /* some kind of exit */ - - if (q.qmagic != ADNS_Q_MAGIC) - { - syslog(LOG_ERR, "error in input from master: bad magic"); - return HES_BAD_MAGIC; - } - - a.amagic = ADNS_A_MAGIC; - a.serial = q.serial; - a.continuation = NULL; - - a.result = res_nquery(statp, q.name_buf, C_IN, q.type, a.ans, sizeof(a.ans)); - a.h_errno_val = h_errno; - - a.len = offsetof(struct adns_answer, ans) + (a.result < 0? 0 : a.result); - -#ifdef DEBUG - if (((q.debugging & IMPAIR_DELAY_ADNS_KEY_ANSWER) && q.type == T_KEY) - || ((q.debugging & IMPAIR_DELAY_ADNS_TXT_ANSWER) && q.type == T_TXT)) - sleep(30); /* delay the answer */ -#endif - - /* write answer, possibly a bit at a time */ - r = write_pipe(afd, (const unsigned char *)&a); - - if (r != HES_CONTINUE) - return r; /* some kind of exit */ - } -} - -/**************** master process ****************/ - -bool eof_from_pluto = FALSE; -#define PLUTO_QFD 0 /* queries come on stdin */ -#define PLUTO_AFD 1 /* answers go out on stdout */ - -#ifndef MAX_WORKERS -# define MAX_WORKERS 10 /* number of in-flight queries */ -#endif - -struct worker_info { - int qfd; /* query pipe's file descriptor */ - int afd; /* answer pipe's file descriptor */ - pid_t pid; - bool busy; - void *continuation; /* of outstanding request */ -}; - -static struct worker_info wi[MAX_WORKERS]; -static struct worker_info *wi_roof = wi; - -/* request FIFO */ - -struct query_list { - struct query_list *next; - struct adns_query aq; -}; - -static struct query_list *oldest_query = NULL; -static struct query_list *newest_query; /* undefined when oldest == NULL */ -static struct query_list *free_queries = NULL; - -static bool -spawn_worker(void) -{ - int qfds[2]; - int afds[2]; - pid_t p; - - if (pipe(qfds) != 0 || pipe(afds) != 0) - { - syslog(LOG_ERR, "pipe(2) failed: %s", strerror(errno)); - exit(HES_PIPE); - } - - wi_roof->qfd = qfds[1]; /* write end of query pipe */ - wi_roof->afd = afds[0]; /* read end of answer pipe */ - - p = fork(); - if (p == -1) - { - /* fork failed: ignore if at least one worker exists */ - if (wi_roof == wi) - { - syslog(LOG_ERR, "fork(2) error creating first worker: %s", strerror(errno)); - exit(HES_FORK); - } - close(qfds[0]); - close(qfds[1]); - close(afds[0]); - close(afds[1]); - return FALSE; - } - else if (p == 0) - { - /* child */ - struct worker_info *w; - - close(PLUTO_QFD); - close(PLUTO_AFD); - /* close all master pipes, including ours */ - for (w = wi; w <= wi_roof; w++) - { - close(w->qfd); - close(w->afd); - } - exit(worker(qfds[0], afds[1])); - } - else - { - /* parent */ - struct worker_info *w = wi_roof++; - - w->pid = p; - w->busy = FALSE; - close(qfds[0]); - close(afds[1]); - return TRUE; - } -} - -static void -send_eof(struct worker_info *w) -{ - pid_t p; - int status; - - close(w->qfd); - w->qfd = NULL_FD; - - close(w->afd); - w->afd = NULL_FD; - - /* reap child */ - p = waitpid(w->pid, &status, 0); - /* ignore result -- what could we do with it? */ -} - -static void -forward_query(struct worker_info *w) -{ - struct query_list *q = oldest_query; - - if (q == NULL) - { - if (eof_from_pluto) - send_eof(w); - } - else - { - enum helper_exit_status r - = write_pipe(w->qfd, (const unsigned char *) &q->aq); - - if (r != HES_CONTINUE) - exit(r); - - w->busy = TRUE; - - oldest_query = q->next; - q->next = free_queries; - free_queries = q; - } -} - -static void -query(void) -{ - struct query_list *q = free_queries; - enum helper_exit_status r; - - /* find an unused queue entry */ - if (q == NULL) - { - q = malloc(sizeof(*q)); - if (q == NULL) - { - syslog(LOG_ERR, "malloc(3) failed"); - exit(HES_MALLOC); - } - } - else - { - free_queries = q->next; - } - - r = read_pipe(PLUTO_QFD, (unsigned char *)&q->aq - , sizeof(q->aq), sizeof(q->aq)); - - if (r == HES_OK) - { - /* EOF: we're done, except for unanswered queries */ - struct worker_info *w; - - eof_from_pluto = TRUE; - q->next = free_queries; - free_queries = q; - - /* Send bye-bye to unbusy processes. - * Note that if there are queued queries, there won't be - * any non-busy workers. - */ - for (w = wi; w != wi_roof; w++) - if (!w->busy) - send_eof(w); - } - else if (r != HES_CONTINUE) - { - exit(r); - } - else if (q->aq.qmagic != ADNS_Q_MAGIC) - { - syslog(LOG_ERR, "error in query from Pluto: bad magic"); - exit(HES_BAD_MAGIC); - } - else - { - struct worker_info *w; - - /* got a query */ - - /* add it to FIFO */ - q->next = NULL; - if (oldest_query == NULL) - oldest_query = q; - else - newest_query->next = q; - newest_query = q; - - /* See if any worker available */ - for (w = wi; ; w++) - { - if (w == wi_roof) - { - /* no free worker */ - if (w == wi + MAX_WORKERS) - break; /* no more to be created */ - /* make a new one */ - if (!spawn_worker()) - break; /* cannot create one at this time */ - } - if (!w->busy) - { - /* assign first to free worker */ - forward_query(w); - break; - } - } - } - return; -} - -static void -answer(struct worker_info *w) -{ - struct adns_answer a; - enum helper_exit_status r = read_pipe(w->afd, (unsigned char *)&a - , offsetof(struct adns_answer, ans), sizeof(a)); - - if (r == HES_OK) - { - /* unexpected EOF */ - syslog(LOG_ERR, "unexpected EOF from worker"); - exit(HES_IO_ERROR_IN); - } - else if (r != HES_CONTINUE) - { - exit(r); - } - else if (a.amagic != ADNS_A_MAGIC) - { - syslog(LOG_ERR, "Input from worker error: bad magic"); - exit(HES_BAD_MAGIC); - } - else if (a.continuation != w->continuation) - { - /* answer doesn't match query */ - syslog(LOG_ERR, "Input from worker error: continuation mismatch"); - exit(HES_SYNC); - } - else - { - /* pass the answer on to Pluto */ - enum helper_exit_status r - = write_pipe(PLUTO_AFD, (const unsigned char *) &a); - - if (r != HES_CONTINUE) - exit(r); - w->busy = FALSE; - forward_query(w); - } -} - -/* assumption: input limited; accept blocking on output */ -static int -master(void) -{ - for (;;) - { - fd_set readfds; - int maxfd = PLUTO_QFD; /* approximate lower bound */ - int ndes = 0; - struct worker_info *w; - - FD_ZERO(&readfds); - if (!eof_from_pluto) - { - FD_SET(PLUTO_QFD, &readfds); - ndes++; - } - for (w = wi; w != wi_roof; w++) - { - if (w->busy) - { - FD_SET(w->afd, &readfds); - ndes++; - if (maxfd < w->afd) - maxfd = w->afd; - } - } - - if (ndes == 0) - return HES_OK; /* done! */ - - do { - ndes = select(maxfd + 1, &readfds, NULL, NULL, NULL); - } while (ndes == -1 && errno == EINTR); - if (ndes == -1) - { - syslog(LOG_ERR, "select(2) error: %s", strerror(errno)); - exit(HES_IO_ERROR_SELECT); - } - else if (ndes > 0) - { - if (FD_ISSET(PLUTO_QFD, &readfds)) - { - query(); - ndes--; - } - for (w = wi; ndes > 0 && w != wi_roof; w++) - { - if (w->busy && FD_ISSET(w->afd, &readfds)) - { - answer(w); - ndes--; - } - } - } - } -} - -/* Not to be invoked by strangers -- user hostile. - * Mandatory args: query-fd answer-fd - * Optional arg: -d, signifying "debug". - */ - -static void -adns_usage(const char *fmt, const char *arg) -{ - const char **sp = ipsec_copyright_notice(); - - fprintf(stderr, "INTERNAL TO PLUTO: DO NOT EXECUTE\n"); - - fprintf(stderr, fmt, arg); - fprintf(stderr, "\nstrongSwan "VERSION"\n"); - - for (; *sp != NULL; sp++) - fprintf(stderr, "%s\n", *sp); - - syslog(LOG_ERR, fmt, arg); - exit(HES_INVOCATION); -} - -int -main(int argc UNUSED, char **argv) -{ - int i = 1; - - name = argv[0]; - - while (i < argc) - { - if (streq(argv[i], "-d")) - { - i++; - debug = TRUE; - } - else - { - adns_usage("unexpected argument \"%s\"", argv[i]); - /*NOTREACHED*/ - } - } - - return master(); -} diff --git a/src/pluto/adns.h b/src/pluto/adns.h deleted file mode 100644 index dfbcbaf16..000000000 --- a/src/pluto/adns.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Pluto Asynchronous DNS Helper Program's Header - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef ADNS - -/* dummy struct to make compilers happy */ -struct adns_query { -}; - -#else /* rest of file */ - -/* The interface in RHL6.x and BIND distribution 8.2.2 are different, - * so we build some of our own :-( - */ - -# ifndef NS_MAXDNAME -# define NS_MAXDNAME MAXDNAME /* I hope this is long enough for IPv6 */ -# endif - -# ifndef NS_PACKETSZ -# define NS_PACKETSZ PACKETSZ -# endif - -/* protocol version */ - -#define ADNS_Q_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 4) -#define ADNS_A_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 128 + 4) - -/* note: both struct adns_query and struct adns_answer must start with - * size_t len; - */ - -struct adns_query { - size_t len; - unsigned int qmagic; - unsigned long serial; - lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ - u_char name_buf[NS_MAXDNAME + 2]; - int type; /* T_KEY or T_TXT */ -}; - -struct adns_answer { - size_t len; - unsigned int amagic; - unsigned long serial; - struct adns_continuation *continuation; - int result; - int h_errno_val; - u_char ans[NS_PACKETSZ * 10]; /* very probably bigger than necessary */ -}; - -enum helper_exit_status { - HES_CONTINUE = -1, /* not an exit */ - HES_OK = 0, /* all's well that ends well (perhaps EOF) */ - HES_INVOCATION, /* improper invocation */ - HES_IO_ERROR_SELECT, /* IO error in select() */ - HES_MALLOC, /* malloc failed */ - HES_IO_ERROR_IN, /* error reading pipe */ - HES_IO_ERROR_OUT, /* error reading pipe */ - HES_PIPE, /* pipe(2) failed */ - HES_SYNC, /* answer from worker doesn't match query */ - HES_FORK, /* fork(2) failed */ - HES_RES_INIT, /* resolver initialization failed */ - HES_BAD_LEN, /* implausible .len field */ - HES_BAD_MAGIC, /* .magic field wrong */ -}; -#endif /* ADNS */ diff --git a/src/pluto/alg_info.c b/src/pluto/alg_info.c deleted file mode 100644 index fe27c10b2..000000000 --- a/src/pluto/alg_info.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Algorithm info parsing and creation functions - * Copyright (C) JuanJo Ciarlante - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - - -#include "alg_info.h" -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" -#include "crypto.h" -#include "kernel_alg.h" -#include "ike_alg.h" - -/* - * sadb/ESP aa attrib converters - */ -int alg_info_esp_aa2sadb(int auth) -{ - int sadb_aalg = 0; - - switch(auth) - { - case AUTH_ALGORITHM_HMAC_MD5: - case AUTH_ALGORITHM_HMAC_SHA1: - sadb_aalg = auth + 1; - break; - default: - sadb_aalg = auth; - } - return sadb_aalg; -} - -int alg_info_esp_sadb2aa(int sadb_aalg) -{ - int auth = 0; - - switch(sadb_aalg) - { - case SADB_AALG_MD5HMAC: - case SADB_AALG_SHA1HMAC: - auth = sadb_aalg - 1; - break; - default: - auth = sadb_aalg; - } - return auth; -} - -void alg_info_free(struct alg_info *alg_info) -{ - free(alg_info); -} - -/* - * Raw add routine: only checks for no duplicates - */ -static void __alg_info_esp_add(struct alg_info_esp *alg_info, int ealg_id, - unsigned ek_bits, int aalg_id, unsigned ak_bits) -{ - struct esp_info *esp_info = alg_info->esp; - unsigned cnt = alg_info->alg_info_cnt, i; - - /* check for overflows */ - passert(cnt < countof(alg_info->esp)); - - /* dont add duplicates */ - for (i = 0; i < cnt; i++) - { - if (esp_info[i].esp_ealg_id == ealg_id - && (!ek_bits || esp_info[i].esp_ealg_keylen == ek_bits) - && esp_info[i].esp_aalg_id == aalg_id - && (!ak_bits || esp_info[i].esp_aalg_keylen == ak_bits)) - { - return; - } - } - - esp_info[cnt].esp_ealg_id = ealg_id; - esp_info[cnt].esp_ealg_keylen = ek_bits; - esp_info[cnt].esp_aalg_id = aalg_id; - esp_info[cnt].esp_aalg_keylen = ak_bits; - - /* sadb values */ - esp_info[cnt].encryptalg = ealg_id; - esp_info[cnt].authalg = alg_info_esp_aa2sadb(aalg_id); - alg_info->alg_info_cnt++; - - DBG(DBG_CRYPT, - DBG_log("esp alg added: %s_%d/%s, cnt=%d", - enum_show(&esp_transform_names, ealg_id), ek_bits, - enum_show(&auth_alg_names, aalg_id), - alg_info->alg_info_cnt) - ) -} - -/** - * Returns true if the given alg is an authenticated encryption algorithm - */ -static bool is_authenticated_encryption(int ealg_id) -{ - switch (ealg_id) - { - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_GMAC: - return TRUE; - } - return FALSE; -} - -/* - * Add ESP alg info _with_ logic (policy): - */ -static void alg_info_esp_add(struct alg_info *alg_info, int ealg_id, - int ek_bits, int aalg_id, int ak_bits) -{ - /* Policy: default to 3DES */ - if (ealg_id == 0) - { - ealg_id = ESP_3DES; - } - if (ealg_id > 0) - { - if (is_authenticated_encryption(ealg_id)) - { - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_NONE, 0); - } - else if (aalg_id > 0) - { - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - aalg_id, ak_bits); - } - else - { - /* Policy: default to SHA-1 and MD5 */ - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_HMAC_SHA1, ak_bits); - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_HMAC_MD5, ak_bits); - } - } -} - -static void __alg_info_ike_add (struct alg_info_ike *alg_info, int ealg_id, - unsigned ek_bits, int aalg_id, unsigned ak_bits, - int modp_id) -{ - struct ike_info *ike_info = alg_info->ike; - unsigned cnt = alg_info->alg_info_cnt; - unsigned i; - - /* check for overflows */ - passert(cnt < countof(alg_info->ike)); - - /* dont add duplicates */ - for (i = 0; i < cnt; i++) - { - if (ike_info[i].ike_ealg == ealg_id - && (!ek_bits || ike_info[i].ike_eklen == ek_bits) - && ike_info[i].ike_halg == aalg_id - && (!ak_bits || ike_info[i].ike_hklen == ak_bits) - && ike_info[i].ike_modp==modp_id) - return; - } - - ike_info[cnt].ike_ealg = ealg_id; - ike_info[cnt].ike_eklen = ek_bits; - ike_info[cnt].ike_halg = aalg_id; - ike_info[cnt].ike_hklen = ak_bits; - ike_info[cnt].ike_modp = modp_id; - alg_info->alg_info_cnt++; - - DBG(DBG_CRYPT, - DBG_log("ikg alg added: %s_%d/%s/%s, cnt=%d", - enum_show(&oakley_enc_names, ealg_id), ek_bits, - enum_show(&oakley_hash_names, aalg_id), - enum_show(&oakley_group_names, modp_id), - alg_info->alg_info_cnt) - ) -} - -/* - * Proposals will be built by looping over default_ike_groups array and - * merging alg_info (ike_info) contents - */ - -static int default_ike_groups[] = { - MODP_1536_BIT, - MODP_1024_BIT -}; - -/* - * Add IKE alg info _with_ logic (policy): - */ -static void alg_info_ike_add (struct alg_info *alg_info, int ealg_id, - int ek_bits, int aalg_id, int ak_bits, int modp_id) -{ - int i = 0; - int n_groups = countof(default_ike_groups); - - /* if specified modp_id avoid loop over default_ike_groups */ - if (modp_id) - { - n_groups=0; - goto in_loop; - } - - for (; n_groups--; i++) - { - modp_id = default_ike_groups[i]; -in_loop: - /* Policy: default to 3DES */ - if (ealg_id == 0) - { - ealg_id = OAKLEY_3DES_CBC; - } - if (ealg_id > 0) - { - if (aalg_id > 0) - { - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - aalg_id, ak_bits, - modp_id); - } - else - { - /* Policy: default to MD5 and SHA */ - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - OAKLEY_MD5, ak_bits, - modp_id); - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - OAKLEY_SHA, ak_bits, - modp_id); - } - } - } -} - -static status_t alg_info_add(chunk_t alg, unsigned protoid, - int *ealg, size_t *ealg_keysize, - int *aalg, size_t *aalg_keysize, int *dh_group) -{ - const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len); - - if (token == NULL) - { - return FAILED; - } - switch (token->type) - { - case ENCRYPTION_ALGORITHM: - if (*ealg != 0) - { - return FAILED; - } - *ealg = (protoid == PROTO_ISAKMP) ? - oakley_from_encryption_algorithm(token->algorithm) : - esp_from_encryption_algorithm(token->algorithm); - if (*ealg == 0) - { - return FAILED; - } - *ealg_keysize = token->keysize; - break; - case INTEGRITY_ALGORITHM: - if (*aalg != 0) - { - return FAILED; - } - *aalg = (protoid == PROTO_ISAKMP) ? - oakley_from_integrity_algorithm(token->algorithm) : - esp_from_integrity_algorithm(token->algorithm); - if (*aalg == 0) - { - return FAILED; - } - *aalg_keysize = token->keysize; - break; - case DIFFIE_HELLMAN_GROUP: - if (protoid == PROTO_ISAKMP) - { - if (*dh_group != 0) - { - return FAILED; - } - *dh_group = token->algorithm; - } - break; - default: - return FAILED; - } - return SUCCESS; -} - - -static status_t alg_info_parse_str(struct alg_info *alg_info, char *alg_str) -{ - char *strict, *single; - status_t status = SUCCESS; - - strict = alg_str + strlen(alg_str) - 1; - if (*strict == '!') - { - alg_info->alg_info_flags |= ALG_INFO_F_STRICT; - *strict = '\0'; - } - while ((single = strsep(&alg_str, ","))) - { - chunk_t string = { (u_char *)single, strlen(single) }; - int ealg = 0; - int aalg = 0; - int dh_group = 0; - size_t ealg_keysize = 0; - size_t aalg_keysize = 0; - - eat_whitespace(&string); - - if (string.len > 0) - { - chunk_t alg; - - /* get all token, separated by '-' */ - while (extract_token(&alg, '-', &string)) - { - status |= alg_info_add(alg, alg_info->alg_info_protoid, - &ealg, &ealg_keysize, - &aalg, &aalg_keysize, &dh_group); - } - if (string.len) - { - status |= alg_info_add(string, alg_info->alg_info_protoid, - &ealg, &ealg_keysize, - &aalg, &aalg_keysize, &dh_group); - } - } - if (status == SUCCESS) - - { - switch (alg_info->alg_info_protoid) - { - case PROTO_IPSEC_ESP: - alg_info_esp_add(alg_info, ealg, ealg_keysize, - aalg, aalg_keysize); - break; - case PROTO_ISAKMP: - alg_info_ike_add(alg_info, ealg, ealg_keysize, - aalg, aalg_keysize, - dh_group); - break; - default: - break; - } - } - } - return status; -} - -struct alg_info_esp *alg_info_esp_create_from_str(char *alg_str) -{ - struct alg_info_esp *alg_info_esp; - char esp_buf[BUF_LEN]; - char *pfs_name; - status_t status = SUCCESS; - /* - * alg_info storage should be sized dynamically - * but this may require 2passes to know - * transform count in advance. - */ - alg_info_esp = malloc_thing (struct alg_info_esp); - zero(alg_info_esp); - - pfs_name=strchr(alg_str, ';'); - if (pfs_name) - { - memcpy(esp_buf, alg_str, pfs_name-alg_str); - esp_buf[pfs_name-alg_str] = 0; - alg_str = esp_buf; - pfs_name++; - - /* if pfs strings AND first char is not '0' */ - if (*pfs_name && pfs_name[0] != '0') - { - const proposal_token_t *token; - - token = proposal_get_token(pfs_name, strlen(pfs_name)); - if (token == NULL || token->type != DIFFIE_HELLMAN_GROUP) - { - /* Bomb if pfsgroup not found */ - DBG(DBG_CRYPT, - DBG_log("alg_info_esp_create_from_str(): pfsgroup \"%s\" not found" - , pfs_name) - ) - status = FAILED; - goto out; - } - alg_info_esp->esp_pfsgroup = token->algorithm; - } - } - else - { - alg_info_esp->esp_pfsgroup = 0; - } - alg_info_esp->alg_info_protoid = PROTO_IPSEC_ESP; - status = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str); - -out: - if (status == SUCCESS) - { - alg_info_esp->ref_cnt = 1; - return alg_info_esp; - } - else - { - free(alg_info_esp); - return NULL; - } -} - -struct alg_info_ike *alg_info_ike_create_from_str(char *alg_str) -{ - struct alg_info_ike *alg_info_ike; - /* - * alg_info storage should be sized dynamically - * but this may require 2passes to know - * transform count in advance. - */ - alg_info_ike = malloc_thing (struct alg_info_ike); - zero(alg_info_ike); - alg_info_ike->alg_info_protoid = PROTO_ISAKMP; - - if (alg_info_parse_str((struct alg_info *)alg_info_ike, alg_str) == SUCCESS) - { - alg_info_ike->ref_cnt = 1; - return alg_info_ike; - } - else - { - free(alg_info_ike); - return NULL; - } -} - -/* - * alg_info struct can be shared by - * several connections instances, - * handle free() with ref_cnts - */ -void -alg_info_addref(struct alg_info *alg_info) -{ - if (alg_info != NULL) - { - alg_info->ref_cnt++; - } -} - -void -alg_info_delref(struct alg_info **alg_info_p) -{ - struct alg_info *alg_info = *alg_info_p; - - if (alg_info != NULL) - { - passert(alg_info->ref_cnt != 0); - alg_info->ref_cnt--; - if (alg_info->ref_cnt == 0) - { - alg_info_free(alg_info); - } - *alg_info_p = NULL; - } -} - -/* snprint already parsed transform list (alg_info) */ -int -alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info) -{ - char *ptr = buf; - int np = 0; - struct esp_info *esp_info; - struct ike_info *ike_info; - int cnt; - - switch (alg_info->alg_info_protoid) { - case PROTO_IPSEC_ESP: - { - struct alg_info_esp *alg_info_esp = (struct alg_info_esp *)alg_info; - - ALG_INFO_ESP_FOREACH(alg_info_esp, esp_info, cnt) - { - np = snprintf(ptr, buflen, "%s", - enum_show(&esp_transform_names, esp_info->esp_ealg_id)); - ptr += np; - buflen -= np; - if (esp_info->esp_ealg_keylen) - { - np = snprintf(ptr, buflen, "_%zu", esp_info->esp_ealg_keylen); - ptr += np; - buflen -= np; - } - np = snprintf(ptr, buflen, "/%s, ", - enum_show(&auth_alg_names, esp_info->esp_aalg_id)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - if (alg_info_esp->esp_pfsgroup) - { - np = snprintf(ptr, buflen, "; pfsgroup=%s; ", - enum_show(&oakley_group_names, alg_info_esp->esp_pfsgroup)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - break; - } - - case PROTO_ISAKMP: - ALG_INFO_IKE_FOREACH((struct alg_info_ike *)alg_info, ike_info, cnt) - { - np = snprintf(ptr, buflen, "%s", - enum_show(&oakley_enc_names, ike_info->ike_ealg)); - ptr += np; - buflen -= np; - if (ike_info->ike_eklen) - { - np = snprintf(ptr, buflen, "_%zu", ike_info->ike_eklen); - ptr += np; - buflen -= np; - } - np = snprintf(ptr, buflen, "/%s/%s, ", - enum_show(&oakley_hash_names, ike_info->ike_halg), - enum_show(&oakley_group_names, ike_info->ike_modp)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - break; - default: - np = snprintf(buf, buflen, "INVALID protoid=%d\n" - , alg_info->alg_info_protoid); - ptr += np; - buflen -= np; - goto out; - } - - np = snprintf(ptr, buflen, "%s" - , alg_info->alg_info_flags & ALG_INFO_F_STRICT? - "strict":""); - ptr += np; - buflen -= np; -out: - if (buflen < 0) - { - loglog(RC_LOG_SERIOUS - , "buffer space exhausted in alg_info_snprint_ike(), buflen=%d" - , buflen); - } - - return ptr - buf; -} - -int alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info) -{ - char *ptr = buf; - - int cnt = alg_info->alg_info_cnt; - struct esp_info *esp_info = alg_info->esp; - - while (cnt--) - { - if (kernel_alg_esp_enc_ok(esp_info->esp_ealg_id, 0, NULL) - && kernel_alg_esp_auth_ok(esp_info->esp_aalg_id, NULL)) - { - u_int eklen = (esp_info->esp_ealg_keylen) - ? esp_info->esp_ealg_keylen - : kernel_alg_esp_enc_keylen(esp_info->esp_ealg_id) - * BITS_PER_BYTE; - - u_int aklen = esp_info->esp_aalg_keylen - ? esp_info->esp_aalg_keylen - : kernel_alg_esp_auth_keylen(esp_info->esp_aalg_id) - * BITS_PER_BYTE; - - int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d, ", - esp_info->esp_ealg_id, eklen, - esp_info->esp_aalg_id, aklen); - ptr += ret; - buflen -= ret; - if (buflen < 0) - break; - } - esp_info++; - } - return ptr - buf; -} - -int alg_info_snprint_ike(char *buf, int buflen, struct alg_info_ike *alg_info) -{ - char *ptr = buf; - - int cnt = alg_info->alg_info_cnt; - struct ike_info *ike_info = alg_info->ike; - - while (cnt--) - { - struct encrypt_desc *enc_desc = ike_alg_get_crypter(ike_info->ike_ealg); - struct hash_desc *hash_desc = ike_alg_get_hasher(ike_info->ike_halg); - struct dh_desc *dh_desc = ike_alg_get_dh_group(ike_info->ike_modp); - - if (enc_desc && hash_desc && dh_desc) - { - - u_int eklen = (ike_info->ike_eklen) - ? ike_info->ike_eklen - : enc_desc->keydeflen; - - u_int aklen = (ike_info->ike_hklen) - ? ike_info->ike_hklen - : hash_desc->hash_digest_size * BITS_PER_BYTE; - - int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d-%d, ", - ike_info->ike_ealg, eklen, - ike_info->ike_halg, aklen, - ike_info->ike_modp); - ptr += ret; - buflen -= ret; - if (buflen < 0) - break; - } - ike_info++; - } - return ptr - buf; -} - diff --git a/src/pluto/alg_info.h b/src/pluto/alg_info.h deleted file mode 100644 index 85b88ddff..000000000 --- a/src/pluto/alg_info.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Algorithm info parsing and creation functions - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef ALG_INFO_H -#define ALG_INFO_H - -struct esp_info { - u_int8_t transid; /* ESP transform */ - u_int16_t auth; /* AUTH */ - size_t enckeylen; /* keylength for ESP transform */ - size_t authkeylen; /* keylength for AUTH */ - u_int8_t encryptalg; /* normally encryptalg=transid */ - u_int8_t authalg; /* normally authalg=auth+1 */ -}; - -struct ike_info { - u_int16_t ike_ealg; /* high 16 bit nums for reserved */ - u_int8_t ike_halg; - size_t ike_eklen; - size_t ike_hklen; - u_int16_t ike_modp; -}; - -#define ALG_INFO_COMMON \ - int alg_info_cnt; \ - int ref_cnt; \ - unsigned alg_info_flags; \ - unsigned alg_info_protoid - -struct alg_info { - ALG_INFO_COMMON; -}; - -struct alg_info_esp { - ALG_INFO_COMMON; - struct esp_info esp[64]; - int esp_pfsgroup; -}; - -struct alg_info_ike { - ALG_INFO_COMMON; - struct ike_info ike[64]; -}; -#define esp_ealg_id transid -#define esp_aalg_id auth -#define esp_ealg_keylen enckeylen /* bits */ -#define esp_aalg_keylen authkeylen /* bits */ - -/* alg_info_flags bits */ -#define ALG_INFO_F_STRICT 0x01 - -extern int alg_info_esp_aa2sadb(int auth); -extern int alg_info_esp_sadb2aa(int sadb_aalg); -extern void alg_info_free(struct alg_info *alg_info); -extern void alg_info_addref(struct alg_info *alg_info); -extern void alg_info_delref(struct alg_info **alg_info); -extern struct alg_info_esp* alg_info_esp_create_from_str(char *alg_str); -extern struct alg_info_ike* alg_info_ike_create_from_str(char *alg_str); -extern int alg_info_parse(const char *str); -extern int alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info); -extern int alg_info_snprint_esp(char *buf, int buflen - , struct alg_info_esp *alg_info); -extern int alg_info_snprint_ike(char *buf, int buflen - , struct alg_info_ike *alg_info); -#define ALG_INFO_ESP_FOREACH(ai, ai_esp, i) \ - for (i=(ai)->alg_info_cnt,ai_esp=(ai)->esp; i--; ai_esp++) -#define ALG_INFO_IKE_FOREACH(ai, ai_ike, i) \ - for (i=(ai)->alg_info_cnt,ai_ike=(ai)->ike; i--; ai_ike++) -#endif /* ALG_INFO_H */ diff --git a/src/pluto/builder.c b/src/pluto/builder.c deleted file mode 100644 index a6e05a330..000000000 --- a/src/pluto/builder.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Pluto certificate/CRL/AC builder hooks. - * Copyright (C) 2002-2009 Andreas Steffen - * Copyright (C) 2009 Martin Willi - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "builder.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "certs.h" -#include "crl.h" - -/** - * Load a certificate - */ -static cert_t *builder_load_cert(certificate_type_t type, va_list args) -{ - x509_flag_t flags = 0; - chunk_t blob = chunk_empty; - bool pgp = FALSE; - - while (TRUE) - { - switch (va_arg(args, builder_part_t)) - { - case BUILD_BLOB_PGP: - pgp = TRUE; - /* FALL */ - case BUILD_BLOB_ASN1_DER: - blob = va_arg(args, chunk_t); - continue; - case BUILD_X509_FLAG: - flags |= va_arg(args, x509_flag_t); - continue; - case BUILD_END: - break; - default: - return NULL; - } - break; - } - if (blob.ptr) - { - cert_t *cert = malloc_thing(cert_t); - - *cert = cert_empty; - - if (pgp) - { - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_GPG, - BUILD_BLOB_PGP, blob, - BUILD_END); - } - else - { - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_X509_FLAG, flags, - BUILD_END); - } - if (cert->cert) - { - return cert; - } - plog(" error in X.509 certificate"); - cert_free(cert); - } - return NULL; -} - -/** - * Load a CRL - */ -static x509crl_t *builder_load_crl(certificate_type_t type, va_list args) -{ - chunk_t blob = chunk_empty; - x509crl_t *crl; - - while (TRUE) - { - switch (va_arg(args, builder_part_t)) - { - case BUILD_BLOB_ASN1_DER: - blob = va_arg(args, chunk_t); - continue; - case BUILD_END: - break; - default: - return NULL; - } - break; - } - if (blob.ptr) - { - crl = malloc_thing(x509crl_t); - crl->next = NULL; - crl->distributionPoints = linked_list_create(); - crl->crl = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509_CRL, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); - if (crl->crl) - { - return crl; - } - plog(" error in X.509 crl"); - free_crl(crl); - } - return NULL; -} - -void init_builder(void) -{ - lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, FALSE, - (builder_function_t)builder_load_cert); - lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, FALSE, - (builder_function_t)builder_load_crl); -} - -void free_builder(void) -{ - lib->creds->remove_builder(lib->creds, (builder_function_t)builder_load_cert); - lib->creds->remove_builder(lib->creds, (builder_function_t)builder_load_crl); -} - diff --git a/src/pluto/builder.h b/src/pluto/builder.h deleted file mode 100644 index 784751b7c..000000000 --- a/src/pluto/builder.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Pluto certificate/CRL/AC builder hooks. - * Copyright (C) 2009 Martin Willi - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _BUILDER_H -#define _BUILDER_H - -/* register credential builder hooks */ -extern void init_builder(); -/* unregister credential builder hooks */ -extern void free_builder(); - -#endif /* _BUILDER_H */ diff --git a/src/pluto/ca.c b/src/pluto/ca.c deleted file mode 100644 index 827b98121..000000000 --- a/src/pluto/ca.c +++ /dev/null @@ -1,712 +0,0 @@ -/* Certification Authority (CA) support for IKE authentication - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "ca.h" -#include "certs.h" -#include "whack.h" -#include "fetch.h" -#include "smartcard.h" - -/* chained list of X.509 authority certificates (ca, aa, and ocsp) */ - -static cert_t *x509authcerts = NULL; - -/* chained list of X.509 certification authority information records */ - -static ca_info_t *ca_infos = NULL; - -/* - * Checks if CA a is trusted by CA b - */ -bool trusted_ca(identification_t *a, identification_t *b, int *pathlen) -{ - bool match = FALSE; - - /* no CA b specified -> any CA a is accepted */ - if (b == NULL) - { - *pathlen = (a == NULL) ? 0 : X509_MAX_PATH_LEN; - return TRUE; - } - - /* no CA a specified -> trust cannot be established */ - if (a == NULL) - { - *pathlen = X509_MAX_PATH_LEN; - return FALSE; - } - - *pathlen = 0; - - /* CA a equals CA b -> we have a match */ - if (a->equals(a, b)) - { - return TRUE; - } - - /* CA a might be a subordinate CA of b */ - lock_authcert_list("trusted_ca"); - - while ((*pathlen)++ < X509_MAX_PATH_LEN) - { - certificate_t *certificate; - identification_t *issuer; - cert_t *cacert; - - cacert = get_authcert(a, chunk_empty, X509_CA); - if (cacert == NULL) - { - break; - } - certificate = cacert->cert; - - /* is the certificate self-signed? */ - { - x509_t *x509 = (x509_t*)certificate; - - if (x509->get_flags(x509) & X509_SELF_SIGNED) - { - break; - } - } - - /* does the issuer of CA a match CA b? */ - issuer = certificate->get_issuer(certificate); - match = b->equals(b, issuer); - - /* we have a match and exit the loop */ - if (match) - { - break; - } - /* go one level up in the CA chain */ - a = issuer; - } - - unlock_authcert_list("trusted_ca"); - return match; -} - -/* - * does our CA match one of the requested CAs? - */ -bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca, - int *our_pathlen) -{ - identification_t *ca; - enumerator_t *enumerator; - - /* if no ca is requested than any ca will match */ - if (requested_ca == NULL || requested_ca->get_count(requested_ca) == 0) - { - *our_pathlen = 0; - return TRUE; - } - - *our_pathlen = X509_MAX_PATH_LEN + 1; - - enumerator = requested_ca->create_enumerator(requested_ca); - while (enumerator->enumerate(enumerator, &ca)) - { - int pathlen; - - if (trusted_ca(our_ca, ca, &pathlen) && pathlen < *our_pathlen) - { - *our_pathlen = pathlen; - } - } - enumerator->destroy(enumerator); - - if (*our_pathlen > X509_MAX_PATH_LEN) - { - *our_pathlen = X509_MAX_PATH_LEN; - return FALSE; - } - else - { - return TRUE; - } -} - -/* - * free the first authority certificate in the chain - */ -static void free_first_authcert(void) -{ - cert_t *first = x509authcerts; - - x509authcerts = first->next; - cert_free(first); -} - -/* - * free all CA certificates - */ -void free_authcerts(void) -{ - lock_authcert_list("free_authcerts"); - - while (x509authcerts != NULL) - { - free_first_authcert(); - } - unlock_authcert_list("free_authcerts"); -} - -/* - * get a X.509 authority certificate with a given subject or keyid - */ -cert_t* get_authcert(identification_t *subject, chunk_t keyid, - x509_flag_t auth_flags) -{ - cert_t *cert, *prev_cert = NULL; - - /* the authority certificate list is empty */ - if (x509authcerts == NULL) - { - return NULL; - } - - for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - - /* skip non-matching types of authority certificates */ - if (!(x509->get_flags(x509) & auth_flags)) - { - continue; - } - - /* compare the keyid with the certificate's subjectKeyIdentifier */ - if (keyid.ptr) - { - chunk_t subjectKeyId; - - subjectKeyId = x509->get_subjectKeyIdentifier(x509); - if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) - { - continue; - } - } - - /* compare the subjectDistinguishedNames */ - if (!(subject && certificate->has_subject(certificate, subject)) && - (subject || !keyid.ptr)) - { - continue; - } - - /* found the authcert */ - if (cert != x509authcerts) - { - /* bring the certificate up front */ - prev_cert->next = cert->next; - cert->next = x509authcerts; - x509authcerts = cert; - } - return cert; - } - return NULL; -} - -/* - * add an authority certificate to the chained list - */ -cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags) -{ - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - cert_t *old_cert; - - lock_authcert_list("add_authcert"); - - old_cert = get_authcert(certificate->get_subject(certificate), - x509->get_subjectKeyIdentifier(x509), - auth_flags); - if (old_cert) - { - if (certificate->equals(certificate, old_cert->cert)) - { - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" authcert is already present and identical") - ) - unlock_authcert_list("add_authcert"); - - cert_free(cert); - return old_cert; - } - else - { - /* cert is already present but will be replaced by new cert */ - free_first_authcert(); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" existing authcert deleted") - ) - } - } - - /* add new authcert to chained list */ - cert->next = x509authcerts; - x509authcerts = cert; - cert_share(cert); /* set count to one */ - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" authcert inserted") - ) - unlock_authcert_list("add_authcert"); - return cert; -} - -/* - * Loads authority certificates - */ -void load_authcerts(char *type, char *path, x509_flag_t auth_flags) -{ - enumerator_t *enumerator; - struct stat st; - char *file; - - DBG1(DBG_LIB, "loading %s certificates from '%s'", type, path); - - enumerator = enumerator_create_directory(path); - if (!enumerator) - { - DBG1(DBG_LIB, " reading directory '%s' failed", path); - return; - } - - while (enumerator->enumerate(enumerator, NULL, &file, &st)) - { - cert_t *cert; - - if (!S_ISREG(st.st_mode)) - { - /* skip special file */ - continue; - } - cert = load_cert(file, type, auth_flags); - if (cert) - { - add_authcert(cert, auth_flags); - } - } - enumerator->destroy(enumerator); -} - -/* - * list all X.509 authcerts with given auth flags in a chained list - */ -void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc) -{ - lock_authcert_list("list_authcerts"); - list_x509cert_chain(caption, x509authcerts, auth_flags, utc); - unlock_authcert_list("list_authcerts"); -} - -/* - * get a cacert with a given subject or keyid from an alternative list - */ -static const cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid, - const cert_t *cert) -{ - if (cert == NULL) - { - return NULL; - } - for (; cert != NULL; cert = cert->next) - { - certificate_t *certificate = cert->cert; - - /* compare the keyid with the certificate's subjectKeyIdentifier */ - if (keyid.ptr) - { - x509_t *x509 = (x509_t*)certificate; - chunk_t subjectKeyId; - - subjectKeyId = x509->get_subjectKeyIdentifier(x509); - if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) - { - continue; - } - } - - /* compare the subjectDistinguishedNames */ - if (!certificate->has_subject(certificate, subject)) - { - continue; - } - - /* we found the cacert */ - return cert; - } - return NULL; -} - -/* establish trust into a candidate authcert by going up the trust chain. - * validity and revocation status are not checked. - */ -bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain) -{ - int pathlen; - - lock_authcert_list("trust_authcert_candidate"); - - for (pathlen = 0; pathlen < X509_MAX_PATH_LEN; pathlen++) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - const cert_t *authcert = NULL; - - DBG(DBG_CONTROL, - DBG_log("subject: '%Y'", subject); - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr != NULL) - { - DBG_log("authkey: %#B", &authKeyID); - } - ) - - /* search in alternative chain first */ - authcert = get_alt_cacert(issuer, authKeyID, alt_chain); - - if (authcert != NULL) - { - DBG(DBG_CONTROL, - DBG_log("issuer cacert found in alternative chain") - ) - } - else - { - /* search in trusted chain */ - authcert = get_authcert(issuer, authKeyID, X509_CA); - - if (authcert != NULL) - { - DBG(DBG_CONTROL, - DBG_log("issuer cacert found") - ) - } - else - { - plog("issuer cacert not found"); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; - } - } - - if (!certificate->issued_by(certificate, authcert->cert)) - { - plog("certificate signature is invalid"); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") - ) - - /* check if cert is a self-signed root ca */ - if (pathlen > 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") - ) - unlock_authcert_list("trust_authcert_candidate"); - return TRUE; - } - - /* go up one step in the trust chain */ - cert = authcert; - } - plog("maximum ca path length of %d levels exceeded", X509_MAX_PATH_LEN); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; -} - -/* - * get a CA info record with a given authName or authKeyID - */ -ca_info_t* get_ca_info(identification_t *name, chunk_t keyid) -{ - ca_info_t *ca= ca_infos; - - while (ca != NULL) - { - if ((keyid.ptr) ? same_keyid(keyid, ca->authKeyID) - : name->equals(name, ca->authName)) - { - return ca; - } - ca = ca->next; - } - return NULL; -} - - -/* - * free the dynamic memory used by a ca_info record - */ -static void -free_ca_info(ca_info_t* ca_info) -{ - if (ca_info == NULL) - { - return; - } - ca_info->crluris->destroy_function(ca_info->crluris, free); - DESTROY_IF(ca_info->authName); - free(ca_info->name); - free(ca_info->ldaphost); - free(ca_info->ldapbase); - free(ca_info->ocspuri); - free(ca_info->authKeyID.ptr); - free(ca_info); -} - -/* - * free all CA certificates - */ -void free_ca_infos(void) -{ - while (ca_infos != NULL) - { - ca_info_t *ca = ca_infos; - - ca_infos = ca_infos->next; - free_ca_info(ca); - } -} - -/* - * find a CA information record by name and optionally delete it - */ -bool find_ca_info_by_name(const char *name, bool delete) -{ - ca_info_t **ca_p = &ca_infos; - ca_info_t *ca = *ca_p; - - while (ca != NULL) - { - /* is there already an entry? */ - if (streq(name, ca->name)) - { - if (delete) - { - lock_ca_info_list("find_ca_info_by_name"); - *ca_p = ca->next; - free_ca_info(ca); - plog("deleting ca description \"%s\"", name); - unlock_ca_info_list("find_ca_info_by_name"); - } - return TRUE; - } - ca_p = &ca->next; - ca = *ca_p; - } - return FALSE; -} - -/* - * Create an empty ca_info_t record - */ -ca_info_t* create_ca_info(void) -{ - ca_info_t *ca_info = malloc_thing(ca_info_t); - - memset(ca_info, 0, sizeof(ca_info_t)); - ca_info->crluris = linked_list_create(); - - return ca_info; -} - -/** - * Adds a CA description to a chained list - */ -void add_ca_info(const whack_message_t *msg) -{ - smartcard_t *sc = NULL; - cert_t *cert = NULL; - bool cached_cert = FALSE; - - if (find_ca_info_by_name(msg->name, FALSE)) - { - loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name); - return; - } - - if (scx_on_smartcard(msg->cacert)) - { - /* load CA cert from smartcard */ - cert = scx_load_cert(msg->cacert, &sc, &cached_cert); - } - else - { - /* load CA cert from file */ - cert = load_ca_cert(msg->cacert); - } - - if (cert) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - chunk_t subjectKeyID = x509->get_subjectKeyIdentifier(x509); - ca_info_t *ca = NULL; - - /* does the authname already exist? */ - ca = get_ca_info(subject, subjectKeyID); - - if (ca != NULL) - { - /* ca_info is already present */ - loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found," - "ignoring \"%s\"", ca->name, msg->name); - cert_free(cert); - return; - } - - plog("added ca description \"%s\"", msg->name); - - /* create and initialize new ca_info record */ - ca = create_ca_info(); - - /* name */ - ca->name = clone_str(msg->name); - - /* authName */ - ca->authName = subject->clone(subject); - DBG(DBG_CONTROL, - DBG_log("authname: '%Y'", subject) - ) - - /* authKeyID */ - if (subjectKeyID.ptr) - { - ca->authKeyID = chunk_clone(subjectKeyID); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log("authkey: %#B", &subjectKeyID) - ) - } - - /* ldaphost */ - ca->ldaphost = clone_str(msg->ldaphost); - - /* ldapbase */ - ca->ldapbase = clone_str(msg->ldapbase); - - /* ocspuri */ - if (msg->ocspuri != NULL) - { - if (strncasecmp(msg->ocspuri, "http", 4) == 0) - ca->ocspuri = clone_str(msg->ocspuri); - else - plog(" ignoring ocspuri with unknown protocol"); - } - - /* add crl uris */ - add_distribution_point(ca->crluris, msg->crluri); - add_distribution_point(ca->crluris, msg->crluri2); - - /* strictrlpolicy */ - ca->strictcrlpolicy = msg->whack_strict; - - /* insert ca_info record into the chained list */ - lock_ca_info_list("add_ca_info"); - - ca->next = ca_infos; - ca_infos = ca; - - unlock_ca_info_list("add_ca_info"); - - /* add cacert to list of authcerts */ - cert = add_authcert(cert, X509_CA); - if (!cached_cert && sc != NULL) - { - if (sc->last_cert != NULL) - { - sc->last_cert->count--; - } - sc->last_cert = cert; - cert_share(sc->last_cert); - } - if (sc != NULL) - time(&sc->last_load); - } -} - -/* - * list all ca_info records in the chained list - */ -void list_ca_infos(bool utc) -{ - ca_info_t *ca = ca_infos; - - if (ca != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 CA Information Records:"); - } - - while (ca != NULL) - { - /* strictpolicy per CA not supported yet - * - whack_log(RC_COMMENT, "%T, \"%s\", strictcrlpolicy: %s" - , &ca->installed, utc, ca->name - , ca->strictcrlpolicy? "yes":"no"); - */ - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " authname: \"%Y\"", ca->authName); - if (ca->ldaphost) - { - whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost); - } - if (ca->ldapbase) - { - whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase); - } - if (ca->ocspuri) - { - whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri); - } - - list_distribution_points(ca->crluris); - - if (ca->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &ca->authKeyID); - } - ca = ca->next; - } -} - diff --git a/src/pluto/ca.h b/src/pluto/ca.h deleted file mode 100644 index d964a694a..000000000 --- a/src/pluto/ca.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Certification Authority (CA) support for IKE authentication - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CA_H -#define _CA_H - -#include -#include - -#include "certs.h" -#include "whack.h" - -/* CA info structures */ - -typedef struct ca_info ca_info_t; - -struct ca_info { - ca_info_t *next; - char *name; - identification_t *authName; - chunk_t authKeyID; - char *ldaphost; - char *ldapbase; - char *ocspuri; - linked_list_t *crluris; - bool strictcrlpolicy; -}; - -extern bool trusted_ca(identification_t *a, identification_t *b, int *pathlen); -extern bool match_requested_ca(linked_list_t *requested_ca, - identification_t *our_ca, int *our_pathlen); -extern cert_t* get_authcert(identification_t *subject, chunk_t keyid, - x509_flag_t auth_flags); -extern void load_authcerts(char *type, char *path, x509_flag_t auth_flags); -extern cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags); -extern void free_authcerts(void); -extern void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc); -extern bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain); -extern ca_info_t* get_ca_info(identification_t *name, chunk_t keyid); -extern bool find_ca_info_by_name(const char *name, bool delete); -extern void add_ca_info(const whack_message_t *msg); -extern void delete_ca_info(const char *name); -extern void free_ca_infos(void); -extern void list_ca_infos(bool utc); - -#endif /* _CA_H */ - diff --git a/src/pluto/certs.c b/src/pluto/certs.c deleted file mode 100644 index e866022df..000000000 --- a/src/pluto/certs.c +++ /dev/null @@ -1,268 +0,0 @@ -/* Certificate support for IKE authentication - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "certs.h" -#include "whack.h" -#include "fetch.h" -#include "keys.h" -#include "builder.h" - -/** - * Initialization - */ -const cert_t cert_empty = { - NULL , /* cert */ - NULL , /* *next */ - 0 , /* count */ - FALSE /* smartcard */ -}; - -/** - * Chained lists of X.509 and PGP end entity certificates - */ -static cert_t *certs = NULL; - -/** - * Free a pluto certificate - */ -void cert_free(cert_t *cert) -{ - if (cert) - { - certificate_t *certificate = cert->cert; - - if (certificate) - { - certificate->destroy(certificate); - } - free(cert); - } -} - -/** - * Add a pluto end entity certificate to the chained list - */ -cert_t* cert_add(cert_t *cert) -{ - certificate_t *certificate = cert->cert; - cert_t *c; - - lock_certs_and_keys("cert_add"); - - for (c = certs; c != NULL; c = c->next) - { - if (certificate->equals(certificate, c->cert)) - { /* already in chain, free cert */ - unlock_certs_and_keys("cert_add"); - cert_free(cert); - return c; - } - } - - /* insert new cert at the root of the chain */ - cert->next = certs; - certs = cert; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" cert inserted") - ) - unlock_certs_and_keys("cert_add"); - return cert; -} - -/** - * Loads a X.509 or OpenPGP certificate - */ -cert_t* load_cert(char *filename, const char *label, x509_flag_t flags) -{ - cert_t *cert; - - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, - BUILD_FROM_FILE, filename, - BUILD_X509_FLAG, flags, - BUILD_END); - if (cert) - { - plog(" loaded %s certificate from '%s'", label, filename); - } - return cert; -} - -/** - * Loads a host certificate - */ -cert_t* load_host_cert(char *filename) -{ - char *path = concatenate_paths(HOST_CERT_PATH, filename); - - return load_cert(path, "host", X509_NONE); -} - -/** - * Loads a CA certificate - */ -cert_t* load_ca_cert(char *filename) -{ - char *path = concatenate_paths(CA_CERT_PATH, filename); - - return load_cert(path, "CA", X509_NONE); -} - -/** - * for each link pointing to the certificate increase the count by one - */ -void cert_share(cert_t *cert) -{ - if (cert != NULL) - { - cert->count++; - } -} - -/* release of a certificate decreases the count by one - * the certificate is freed when the counter reaches zero - */ -void cert_release(cert_t *cert) -{ - if (cert && --cert->count == 0) - { - cert_t **pp = &certs; - while (*pp != cert) - { - pp = &(*pp)->next; - } - *pp = cert->next; - cert_free(cert); - } -} - -/** - * Get a X.509 certificate with a given issuer found at a certain position - */ -cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t *chain) -{ - cert_t *cert = chain ? chain->next : certs; - - while (cert) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - - if (keyid.ptr ? same_keyid(keyid, authKeyID) : - certificate->has_issuer(certificate, issuer)) - { - return cert; - } - cert = cert->next; - } - return NULL; -} - -/** - * List all PGP end certificates in a chained list - */ -void list_pgp_end_certs(bool utc) -{ - cert_t *cert = certs; - time_t now = time(NULL); - bool first = TRUE; - - - while (cert != NULL) - { - certificate_t *certificate = cert->cert; - - if (certificate->get_type(certificate) == CERT_GPG) - { - time_t created, until; - public_key_t *key; - identification_t *userid = certificate->get_subject(certificate); - pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; - chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); - - if (first) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of PGP End Entity Certificates:"); - first = false; - } - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " userid: '%Y'", userid); - whack_log(RC_COMMENT, " digest: %#B", &fingerprint); - - /* list validity */ - certificate->get_validity(certificate, &now, &created, &until); - whack_log(RC_COMMENT, " created: %T", &created, utc); - whack_log(RC_COMMENT, " until: %T %s%s", &until, utc, - check_expiry(until, CA_CERT_WARNING_INTERVAL, TRUE), - (until == TIME_32_BIT_SIGNED_MAX) ? " (expires never)":""); - - key = certificate->get_public_key(certificate); - if (key) - { - chunk_t keyid; - - whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", - key_type_names, key->get_type(key), - key->get_keysize(key), - has_private_key(cert)? ", has private key" : ""); - if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - whack_log(RC_COMMENT, " keyid: %#B", &keyid); - } - if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &keyid)) - { - whack_log(RC_COMMENT, " subjkey: %#B", &keyid); - } - } - } - cert = cert->next; - } -} - -/** - * List all X.509 end certificates in a chained list - */ -void list_x509_end_certs(bool utc) -{ - list_x509cert_chain("End Entity", certs, X509_NONE, utc); -} - -/** - * list all X.509 and OpenPGP end certificates - */ -void cert_list(bool utc) -{ - list_x509_end_certs(utc); - list_pgp_end_certs(utc); -} - diff --git a/src/pluto/certs.h b/src/pluto/certs.h deleted file mode 100644 index b31c4c3ed..000000000 --- a/src/pluto/certs.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Certificate support for IKE authentication - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CERTS_H -#define _CERTS_H - -#include -#include -#include - -#include - -#include "defs.h" - -/* path definitions for private keys, end certs, - * cacerts, attribute certs and crls - */ -#define PRIVATE_KEY_PATH IPSEC_CONFDIR "/ipsec.d/private" -#define HOST_CERT_PATH IPSEC_CONFDIR "/ipsec.d/certs" -#define CA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/cacerts" -#define A_CERT_PATH IPSEC_CONFDIR "/ipsec.d/acerts" -#define AA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/aacerts" -#define OCSP_CERT_PATH IPSEC_CONFDIR "/ipsec.d/ocspcerts" -#define CRL_PATH IPSEC_CONFDIR "/ipsec.d/crls" -#define REQ_PATH IPSEC_CONFDIR "/ipsec.d/reqs" - -/* advance warning of imminent expiry of - * cacerts, public keys, and crls - */ -#define CA_CERT_WARNING_INTERVAL 30 /* days */ -#define OCSP_CERT_WARNING_INTERVAL 30 /* days */ -#define PUBKEY_WARNING_INTERVAL 7 /* days */ -#define CRL_WARNING_INTERVAL 7 /* days */ -#define ACERT_WARNING_INTERVAL 1 /* day */ - -/* access structure for a pluto certificate */ - -typedef struct cert_t cert_t; - -struct cert_t { - certificate_t *cert; - cert_t *next; - int count; - bool smartcard; -}; - -/* used for initialization */ -extern const cert_t cert_empty; - -/* do not send certificate requests - * flag set in plutomain.c and used in ipsec_doi.c - */ -extern bool no_cr_send; - -extern cert_t* load_cert(char *filename, const char *label, x509_flag_t flags); -extern cert_t* load_host_cert(char *filename); -extern cert_t* load_ca_cert(char *filename); -extern cert_t* cert_add(cert_t *cert); -extern void cert_free(cert_t *cert); -extern void cert_share(cert_t *cert); -extern void cert_release(cert_t *cert); -extern void cert_list(bool utc); -extern cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t* chain); - -#endif /* _CERTS_H */ - - diff --git a/src/pluto/connections.c b/src/pluto/connections.c deleted file mode 100644 index 27cec40fc..000000000 --- a/src/pluto/connections.c +++ /dev/null @@ -1,4507 +0,0 @@ -/* information about connections between hosts and clients - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* missing from on old systems */ -#include - -#include -#include "kameipsec.h" - -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "x509.h" -#include "ca.h" -#include "crl.h" -#include "certs.h" -#include "ac.h" -#include "smartcard.h" -#include "fetch.h" -#include "connections.h" -#include "foodgroups.h" -#include "demux.h" -#include "state.h" -#include "timer.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "server.h" -#include "kernel.h" -#include "log.h" -#include "keys.h" -#include "adns.h" /* needs */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "whack.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "kernel_alg.h" -#include "nat_traversal.h" -#include "virtual.h" -#include "whack_attribute.h" -#include "modecfg.h" - -static void flush_pending_by_connection(connection_t *c); /* forward */ - -static connection_t *connections = NULL; - -/* struct host_pair: a nexus of information about a pair of hosts. - * A host is an IP address, UDP port pair. This is a debatable choice: - * - should port be considered (no choice of port in standard)? - * - should ID be considered (hard because not always known)? - * - should IP address matter on our end (we don't know our end)? - * Only oriented connections are registered. - * Unoriented connections are kept on the unoriented_connections - * linked list (using hp_next). For them, host_pair is NULL. - */ - -struct host_pair { - struct { - ip_address addr; - u_int16_t port; /* host order */ - } me, him; - bool initial_connection_sent; - connection_t *connections; /* connections with this pair */ - struct pending *pending; /* awaiting Keying Channel */ - struct host_pair *next; -}; - -static struct host_pair *host_pairs = NULL; - -static connection_t *unoriented_connections = NULL; - -/** - * Check if an id was instantiated by assigning to it the current IP address - */ -bool his_id_was_instantiated(const connection_t *c) -{ - if (c->kind != CK_INSTANCE) - { - return FALSE; - } - if (id_is_ipaddr(c->spd.that.id)) - { - identification_t *host; - bool equal; - - host = identification_create_from_sockaddr((sockaddr_t*)&c->spd.that.host_addr); - equal = host->equals(host, c->spd.that.id); - host->destroy(host); - return equal; - } - else - { - return TRUE; - } -} - -/** - * Check to see that IDs of peers match - */ -bool same_peer_ids(const connection_t *c, const connection_t *d, - identification_t *his_id) -{ - return d->spd.this.id->equals(d->spd.this.id, c->spd.this.id) && - d->spd.that.id->equals(d->spd.that.id, - his_id ? his_id : c->spd.that.id); -} - -static struct host_pair *find_host_pair(const ip_address *myaddr, - u_int16_t myport, - const ip_address *hisaddr, - u_int16_t hisport) -{ - struct host_pair *p, *prev; - - /* default hisaddr to an appropriate any */ - if (hisaddr == NULL) - hisaddr = aftoinfo(addrtypeof(myaddr))->any; - - if (nat_traversal_enabled) - { - /** - * port is not relevant in host_pair. with nat_traversal we - * always use pluto_port (500) - */ - myport = pluto_port; - hisport = pluto_port; - } - - for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next) - { - if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport - && sameaddr(&p->him.addr, hisaddr) && p->him.port == hisport) - { - if (prev) - { - prev->next = p->next; /* remove p from list */ - p->next = host_pairs; /* and stick it on front */ - host_pairs = p; - } - break; - } - } - return p; -} - -/* find head of list of connections with this pair of hosts */ -static connection_t *find_host_pair_connections(const ip_address *myaddr, - u_int16_t myport, - const ip_address *hisaddr, - u_int16_t hisport) -{ - struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport); - - if (nat_traversal_enabled && hp && hisaddr) - { - connection_t *c; - - for (c = hp->connections; c != NULL; c = c->hp_next) - { - if (c->spd.this.host_port == myport && c->spd.that.host_port == hisport) - return c; - } - return NULL; - } - return hp == NULL? NULL : hp->connections; -} - -static void connect_to_host_pair(connection_t *c) -{ - if (oriented(*c)) - { - struct host_pair *hp; - - ip_address his_addr = (c->spd.that.allow_any) - ? *aftoinfo(addrtypeof(&c->spd.that.host_addr))->any - : c->spd.that.host_addr; - - hp = find_host_pair(&c->spd.this.host_addr, c->spd.this.host_port - , &his_addr, c->spd.that.host_port); - - if (hp == NULL) - { - /* no suitable host_pair -- build one */ - hp = malloc_thing(struct host_pair); - hp->me.addr = c->spd.this.host_addr; - hp->him.addr = his_addr; - hp->me.port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port; - hp->him.port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port; - hp->initial_connection_sent = FALSE; - hp->connections = NULL; - hp->pending = NULL; - hp->next = host_pairs; - host_pairs = hp; - } - c->host_pair = hp; - c->hp_next = hp->connections; - hp->connections = c; - } - else - { - /* since this connection isn't oriented, we place it - * in the unoriented_connections list instead. - */ - c->host_pair = NULL; - c->hp_next = unoriented_connections; - unoriented_connections = c; - } -} - -/* find a connection by name. - * If strict, don't accept a CK_INSTANCE. - * Move the winner (if any) to the front. - * If none is found, and strict, a diagnostic is logged to whack. - */ -connection_t *con_by_name(const char *nm, bool strict) -{ - connection_t *p, *prev; - - for (prev = NULL, p = connections; ; prev = p, p = p->ac_next) - { - if (p == NULL) - { - if (strict) - whack_log(RC_UNKNOWN_NAME - , "no connection named \"%s\"", nm); - break; - } - if (streq(p->name, nm) - && (!strict || p->kind != CK_INSTANCE)) - { - if (prev) - { - prev->ac_next = p->ac_next; /* remove p from list */ - p->ac_next = connections; /* and stick it on front */ - connections = p; - } - break; - } - } - return p; -} - -void release_connection(connection_t *c, bool relations) -{ - if (c->kind == CK_INSTANCE) - { - /* This does everything we need. - * Note that we will be called recursively by delete_connection, - * but kind will be CK_GOING_AWAY. - */ - delete_connection(c, relations); - } - else - { - flush_pending_by_connection(c); - delete_states_by_connection(c, relations); - unroute_connection(c); - } -} - -/* Delete a connection */ - -#define list_rm(etype, enext, e, ehead) { \ - etype **ep; \ - for (ep = &(ehead); *ep != (e); ep = &(*ep)->enext) \ - passert(*ep != NULL); /* we must not come up empty-handed */ \ - *ep = (e)->enext; \ - } - - -void delete_connection(connection_t *c, bool relations) -{ - modecfg_attribute_t *ca; - connection_t *old_cur_connection; - identification_t *client_id; - - old_cur_connection = cur_connection == c? NULL : cur_connection; -#ifdef DEBUG - lset_t old_cur_debugging = cur_debugging; -#endif - - set_cur_connection(c); - - /* Must be careful to avoid circularity: - * we mark c as going away so it won't get deleted recursively. - */ - passert(c->kind != CK_GOING_AWAY); - if (c->kind == CK_INSTANCE) - { - plog("deleting connection \"%s\" instance with peer %s {isakmp=#%lu/ipsec=#%lu}" - , c->name - , ip_str(&c->spd.that.host_addr) - , c->newest_isakmp_sa, c->newest_ipsec_sa); - c->kind = CK_GOING_AWAY; - } - else - { - plog("deleting connection"); - } - release_connection(c, relations); /* won't delete c */ - - if (c->kind == CK_GROUP) - { - delete_group(c); - } - - /* free up any logging resources */ - perpeer_logfree(c); - - /* find and delete c from connections list */ - list_rm(connection_t, ac_next, c, connections); - cur_connection = old_cur_connection; - - /* find and delete c from the host pair list */ - if (c->host_pair == NULL) - { - if (c->ikev1) - { - list_rm(connection_t, hp_next, c, unoriented_connections); - } - } - else - { - struct host_pair *hp = c->host_pair; - - list_rm(connection_t, hp_next, c, hp->connections); - c->host_pair = NULL; /* redundant, but safe */ - - /* if there are no more connections with this host_pair - * and we haven't even made an initial contact, let's delete - * this guy in case we were created by an attempted DOS attack. - */ - if (hp->connections == NULL - && !hp->initial_connection_sent) - { - passert(hp->pending == NULL); /* ??? must deal with this! */ - list_rm(struct host_pair, next, hp, host_pairs); - free(hp); - } - } - if (c->kind != CK_GOING_AWAY) - { - free(c->spd.that.virt); - } - - client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - /* release virtual IP address lease if any */ - if (c->spd.that.modecfg && c->spd.that.pool && - !c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - hydra->attributes->release_address(hydra->attributes, c->spd.that.pool, - c->spd.that.host_srcip, client_id); - } - - /* release requested attributes if any */ - if (c->requested) - { - c->requested->destroy_function(c->requested, - (void*)modecfg_attribute_destroy); - } - - /* release other attributes if any */ - if (c->attributes) - { - while (c->attributes->remove_last(c->attributes, (void **)&ca) == SUCCESS) - { - hydra->attributes->release(hydra->attributes, ca->handler, - client_id, ca->type, ca->value); - modecfg_attribute_destroy(ca); - } - c->attributes->destroy(c->attributes); - } - - if (c->kind != CK_GOING_AWAY) - { - whack_attr->del_pool(whack_attr, c->name); - } - - /* free internal data */ -#ifdef DEBUG - cur_debugging = old_cur_debugging; -#endif - free(c->name); - DESTROY_IF(c->xauth_identity); - DESTROY_IF(c->spd.this.id); - DESTROY_IF(c->spd.this.ca); - DESTROY_IF(c->spd.this.groups); - DESTROY_IF(c->spd.this.host_srcip); - free(c->spd.this.updown); - free(c->spd.this.pool); - DESTROY_IF(c->spd.that.id); - DESTROY_IF(c->spd.that.ca); - DESTROY_IF(c->spd.that.groups); - DESTROY_IF(c->spd.that.host_srcip); - free(c->spd.that.updown); - free(c->spd.that.pool); - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - } -#ifdef ADNS - gw_delref(&c->gw_info); -#endif - lock_certs_and_keys("delete_connection"); - cert_release(c->spd.this.cert); - scx_release(c->spd.this.sc); - cert_release(c->spd.that.cert); - scx_release(c->spd.that.sc); - unlock_certs_and_keys("delete_connection"); - - alg_info_delref((struct alg_info **)&c->alg_info_esp); - alg_info_delref((struct alg_info **)&c->alg_info_ike); - - free(c); -} - -/* Delete connections with the specified name */ -void delete_connections_by_name(const char *name, bool strict) -{ - connection_t *c = con_by_name(name, strict); - - for (; c != NULL; c = con_by_name(name, FALSE)) - delete_connection(c, FALSE); -} - -void delete_every_connection(void) -{ - while (connections) - { - delete_connection(connections, TRUE); - } -} - -void release_dead_interfaces(void) -{ - struct host_pair *hp; - - for (hp = host_pairs; hp != NULL; hp = hp->next) - { - connection_t **pp - , *p; - - for (pp = &hp->connections; (p = *pp) != NULL; ) - { - if (p->interface->change == IFN_DELETE) - { - /* this connection's interface is going away */ - enum connection_kind k = p->kind; - - release_connection(p, TRUE); - - if (k <= CK_PERMANENT) - { - /* The connection should have survived release: - * move it to the unoriented_connections list. - */ - passert(p == *pp); - - p->interface = NULL; - - *pp = p->hp_next; /* advance *pp */ - p->host_pair = NULL; - p->hp_next = unoriented_connections; - unoriented_connections = p; - } - else - { - /* The connection should have vanished, - * but the previous connection remains. - */ - passert(p != *pp); - } - } - else - { - pp = &p->hp_next; /* advance pp */ - } - } - } -} - -/* adjust orientations of connections to reflect newly added interfaces */ -void check_orientations(void) -{ - /* try to orient all the unoriented connections */ - { - connection_t *c = unoriented_connections; - - unoriented_connections = NULL; - - while (c) - { - connection_t *nxt = c->hp_next; - - (void)orient(c); - connect_to_host_pair(c); - c = nxt; - } - } - - /* Check that no oriented connection has become double-oriented. - * In other words, the far side must not match one of our new interfaces. - */ - { - struct iface *i; - - for (i = interfaces; i != NULL; i = i->next) - { - if (i->change == IFN_ADD) - { - struct host_pair *hp; - - for (hp = host_pairs; hp != NULL; hp = hp->next) - { - if (sameaddr(&hp->him.addr, &i->addr) - && hp->him.port == pluto_port) - { - /* bad news: the whole chain of connections - * hanging off this host pair has both sides - * matching an interface. - * We'll get rid of them, using orient and - * connect_to_host_pair. But we'll be lazy - * and not ditch the host_pair itself (the - * cost of leaving it is slight and cannot - * be induced by a foe). - */ - connection_t *c = hp->connections; - - hp->connections = NULL; - while (c) - { - connection_t *nxt = c->hp_next; - - c->interface = NULL; - (void)orient(c); - connect_to_host_pair(c); - c = nxt; - } - } - } - } - } - } -} - -static err_t default_end(struct end *e, ip_address *dflt_nexthop) -{ - err_t ugh = NULL; - int af = addrtypeof(&e->host_addr); - - if (af != AF_INET && af != AF_INET6) - { - return "unknown address family in default_end"; - } - - /* default ID to IP (but only if not NO_IP -- WildCard) */ - if (e->id->get_type(e->id) == ID_ANY && !isanyaddr(&e->host_addr)) - { - e->id->destroy(e->id); - e->id = identification_create_from_sockaddr((sockaddr_t*)&e->host_addr); - e->has_id_wildcards = FALSE; - } - - /* default nexthop to other side */ - if (isanyaddr(&e->host_nexthop)) - { - e->host_nexthop = *dflt_nexthop; - } - - /* default client to subnet containing only self - * XXX This may mean that the client's address family doesn't match - * tunnel_addr_family. - */ - if (!e->has_client) - { - ugh = addrtosubnet(&e->host_addr, &e->client); - } - return ugh; -} - -/* Format the topology of a connection end, leaving out defaults. - * Largest left end looks like: client === host : port [ host_id ] --- hop - * Note: if that==NULL, skip nexthop - * Returns strlen of formated result (length excludes NUL at end). - */ -size_t format_end(char *buf, size_t buf_len, const struct end *this, - const struct end *that, bool is_left, lset_t policy) -{ - char client[BUF_LEN]; - const char *client_sep = ""; - char protoport[sizeof(":255/65535")]; - const char *host = NULL; - char host_space[ADDRTOT_BUF]; - char host_port[sizeof(":65535")]; - char host_id[BUF_LEN + 2]; - char hop[ADDRTOT_BUF]; - const char *hop_sep = ""; - const char *open_brackets = ""; - const char *close_brackets = ""; - - if (isanyaddr(&this->host_addr)) - { - switch (policy & (POLICY_GROUP | POLICY_OPPO)) - { - case POLICY_GROUP: - host = "%group"; - break; - case POLICY_OPPO: - host = "%opportunistic"; - break; - case POLICY_GROUP | POLICY_OPPO: - host = "%opportunisticgroup"; - break; - default: - host = "%any"; - break; - } - } - - client[0] = '\0'; - - if (is_virtual_end(this) && isanyaddr(&this->host_addr)) - { - host = "%virtual"; - } - - /* [client===] */ - if (this->has_client) - { - ip_address client_net, client_mask; - - networkof(&this->client, &client_net); - maskof(&this->client, &client_mask); - client_sep = "==="; - - /* {client_subnet_wildcard} */ - if (this->has_client_wildcard) - { - open_brackets = "{"; - close_brackets = "}"; - } - - if (isanyaddr(&client_net) && isanyaddr(&client_mask) - && (policy & (POLICY_GROUP | POLICY_OPPO))) - { - client_sep = ""; /* boring case */ - } - else if (subnetisnone(&this->client)) - { - strncpy(client, "?", sizeof(client)); - } - else - { - subnettot(&this->client, 0, client, sizeof(client)); - } - } - else if (this->modecfg && this->host_srcip->is_anyaddr(this->host_srcip)) - { - /* we are mode config client, or a server with a pool */ - client_sep = "==="; - client[0] = '%'; - strncpy(client+1, this->pool ?: "modecfg", sizeof(client)-1); - } - - /* host */ - if (host == NULL) - { - addrtot(&this->host_addr, 0, host_space, sizeof(host_space)); - host = host_space; - } - - host_port[0] = '\0'; - if (this->host_port != IKE_UDP_PORT) - { - snprintf(host_port, sizeof(host_port), ":%u", this->host_port); - } - - /* payload portocol and port */ - protoport[0] = '\0'; - if (this->has_port_wildcard) - { - snprintf(protoport, sizeof(protoport), ":%u/%%any", this->protocol); - } - else if (this->port || this->protocol) - { - snprintf(protoport, sizeof(protoport), ":%u/%u", this->protocol - , this->port); - } - - /* id */ - snprintf(host_id, sizeof(host_id), "[%Y]", this->id); - - /* [---hop] */ - hop[0] = '\0'; - hop_sep = ""; - if (that && !sameaddr(&this->host_nexthop, &that->host_addr)) - { - addrtot(&this->host_nexthop, 0, hop, sizeof(hop)); - hop_sep = "---"; - } - - if (is_left) - { - snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s%s" - , open_brackets, client, close_brackets, client_sep - , this->allow_any? "%":"" - , host, host_port, host_id, protoport - , hop_sep, hop); - } - else - { - snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s%s" - , hop, hop_sep - , this->allow_any? "%":"" - , host, host_port, host_id, protoport, client_sep - , open_brackets, client, close_brackets); - } - return strlen(buf); -} - -/* format topology of a connection. - * Two symmetric ends separated by ... - */ -#define CONNECTION_BUF (2 * (END_BUF - 1) + 4) - -static size_t format_connection(char *buf, size_t buf_len, - const connection_t *c, - struct spd_route *sr) -{ - size_t w = format_end(buf, buf_len, &sr->this, &sr->that, TRUE, LEMPTY); - - w += snprintf(buf + w, buf_len - w, "..."); - return w + format_end(buf + w, buf_len - w, &sr->that, &sr->this, FALSE, c->policy); -} - -static void unshare_connection_strings(connection_t *c) -{ - c->name = clone_str(c->name); - if (c->xauth_identity) - { - c->xauth_identity = c->xauth_identity->clone(c->xauth_identity); - } - c->spd.this.id = c->spd.this.id->clone(c->spd.this.id); - c->spd.this.pool = clone_str(c->spd.this.pool); - c->spd.this.updown = clone_str(c->spd.this.updown); - c->spd.this.host_srcip = c->spd.this.host_srcip->clone(c->spd.this.host_srcip); - scx_share(c->spd.this.sc); - cert_share(c->spd.this.cert); - if (c->spd.this.ca) - { - c->spd.this.ca = c->spd.this.ca->clone(c->spd.this.ca); - } - if (c->spd.this.groups) - { - c->spd.this.groups = c->spd.this.groups->get_ref(c->spd.this.groups); - } - c->spd.that.id = c->spd.that.id->clone(c->spd.that.id); - c->spd.that.pool = clone_str(c->spd.that.pool); - c->spd.that.updown = clone_str(c->spd.that.updown); - c->spd.that.host_srcip = c->spd.that.host_srcip->clone(c->spd.that.host_srcip); - scx_share(c->spd.that.sc); - cert_share(c->spd.that.cert); - if (c->spd.that.ca) - { - c->spd.that.ca = c->spd.that.ca->clone(c->spd.that.ca); - } - if (c->spd.that.groups) - { - c->spd.that.groups = c->spd.that.groups->get_ref(c->spd.that.groups); - } - - /* increment references to algo's */ - alg_info_addref((struct alg_info *)c->alg_info_esp); - alg_info_addref((struct alg_info *)c->alg_info_ike); -} - -static void load_end_certificate(char *filename, struct end *dst) -{ - time_t notBefore, notAfter; - cert_t *cert = NULL; - certificate_t *certificate; - bool cached_cert = FALSE; - - /* initialize end certificate */ - dst->cert = NULL; - - /* initialize smartcard info record */ - dst->sc = NULL; - - if (filename) - { - if (scx_on_smartcard(filename)) - { - /* load cert from smartcard */ - cert = scx_load_cert(filename, &dst->sc, &cached_cert); - } - else - { - /* load cert from file */ - cert = load_host_cert(filename); - } - } - - if (cert) - { - certificate = cert->cert; - - if (dst->id->get_type(dst->id) == ID_ANY || - !certificate->has_subject(certificate, dst->id)) - { - plog( " id '%Y' not confirmed by certificate, defaulting to '%Y'", - dst->id, certificate->get_subject(certificate)); - dst->id->destroy(dst->id); - dst->id = certificate->get_subject(certificate); - dst->id = dst->id->clone(dst->id); - } - - if (cached_cert) - { - dst->cert = cert; - } - else - { - if (!certificate->get_validity(certificate, NULL, ¬Before, ¬After)) - { - plog("certificate is invalid (valid from %T to %T)", - ¬Before, FALSE, ¬After, FALSE); - cert_free(cert); - return; - } - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - add_public_key_from_cert(cert, notAfter, DAL_LOCAL); - dst->cert = cert_add(cert); - } - certificate = dst->cert->cert; - - /* if no CA is defined, use issuer as default */ - if (dst->ca == NULL && certificate->get_type(certificate) == CERT_X509) - { - identification_t *issuer; - - issuer = certificate->get_issuer(certificate); - dst->ca = issuer->clone(issuer); - } - - /* cache the certificate that was last retrieved from the smartcard */ - if (dst->sc) - { - if (!dst->sc->last_cert || - !certificate->equals(certificate, dst->sc->last_cert->cert)) - { - lock_certs_and_keys("load_end_certificates"); - cert_release(dst->sc->last_cert); - dst->sc->last_cert = dst->cert; - cert_share(dst->cert); - unlock_certs_and_keys("load_end_certificates"); - } - time(&dst->sc->last_load); - } - } - scx_share(dst->sc); - cert_share(dst->cert); -} - -static bool extract_end(struct end *dst, const whack_end_t *src, - const char *name, bool is_left) -{ - bool same_ca = FALSE; - - dst->is_left = is_left; - dst->id = identification_create_from_string(src->id); - dst->ca = NULL; - - /* decode CA distinguished name, if any */ - if (src->ca) - { - if streq(src->ca, "%same") - { - same_ca = TRUE; - } - else if (!streq(src->ca, "%any")) - { - dst->ca = identification_create_from_string(src->ca); - if (dst->ca->get_type(dst->ca) != ID_DER_ASN1_DN) - { - plog("bad CA string '%s', ignored", src->ca); - dst->ca->destroy(dst->ca); - dst->ca = NULL; - } - } - } - - /* load local end certificate and extract ID, if any */ - load_end_certificate(src->cert, dst); - - /* does id has wildcards? */ - dst->has_id_wildcards = dst->id->contains_wildcards(dst->id); - - /* decode group attributes, if any */ - if (src->groups) - { - dst->groups = ietf_attributes_create_from_string(src->groups); - } - - /* the rest is simple copying of corresponding fields */ - dst->host_addr = src->host_addr; - dst->host_nexthop = src->host_nexthop; - dst->host_srcip = host_create_from_sockaddr((sockaddr_t*)&src->host_srcip); - dst->has_natip = src->has_natip; - dst->client = src->client; - dst->protocol = src->protocol; - dst->port = src->port; - dst->has_port_wildcard = src->has_port_wildcard; - dst->key_from_DNS_on_demand = src->key_from_DNS_on_demand; - dst->has_client = src->has_client; - dst->has_client_wildcard = src->has_client_wildcard; - dst->modecfg = src->modecfg; - dst->hostaccess = src->hostaccess; - dst->allow_any = src->allow_any; - dst->sendcert = src->sendcert; - dst->updown = clone_str(src->updown); - dst->host_port = src->host_port; - - /* if the sourceip netmask is zero a named pool exists */ - if (src->sourceip_mask == 0) - { - dst->pool = clone_str(src->sourceip); - } - - /* if host sourceip is defined but no client is present - * behind the host then set client to sourceip/32 - */ - if (!dst->host_srcip->is_anyaddr(dst->host_srcip) && - !dst->has_natip && !dst->has_client) - { - ip_address addr; - err_t ugh; - - addr = *(ip_address*)dst->host_srcip->get_sockaddr(dst->host_srcip); - ugh = addrtosubnet(&addr, &dst->client); - - if (ugh) - { - plog("could not assign host sourceip to client subnet"); - } - else - { - dst->has_client = TRUE; - } - } - return same_ca; -} - -static bool check_connection_end(const whack_end_t *this, - const whack_end_t *that, - const whack_message_t *wm) -{ - if (wm->addr_family != addrtypeof(&this->host_addr) - || wm->addr_family != addrtypeof(&this->host_nexthop) - || (this->has_client? wm->tunnel_addr_family : wm->addr_family) - != subnettypeof(&this->client) - || subnettypeof(&this->client) != subnettypeof(&that->client)) - { - /* this should have been diagnosed by whack, so we need not be clear - * !!! overloaded use of RC_CLASH - */ - loglog(RC_CLASH, "address family inconsistency in connection"); - return FALSE; - } - - if (isanyaddr(&that->host_addr)) - { - /* other side is wildcard: we must check if other conditions met */ - if (isanyaddr(&this->host_addr)) - { - loglog(RC_ORIENT, "connection must specify host IP address for our side"); - return FALSE; - } - } - - if (this->virt && (!isanyaddr(&this->host_addr) || this->has_client)) - { - loglog(RC_CLASH, - "virtual IP must only be used with %%any and without client"); - return FALSE; - } - - return TRUE; /* happy */ -} - -connection_t *find_connection_by_reqid(uint32_t reqid) -{ - connection_t *c; - - reqid &= ~3; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->spd.reqid == reqid) - { - return c; - } - } - - return NULL; -} - -static uint32_t gen_reqid(void) -{ - uint32_t start; - static uint32_t reqid = IPSEC_MANUAL_REQID_MAX & ~3; - - start = reqid; - do { - reqid += 4; - if (reqid == 0) - { - reqid = (IPSEC_MANUAL_REQID_MAX & ~3) + 4; - } - if (!find_connection_by_reqid(reqid)) - { - return reqid; - } - } while (reqid != start); - - exit_log("unable to allocate reqid"); - return 0; /* never reached ... */ -} - -void add_connection(const whack_message_t *wm) -{ - if (con_by_name(wm->name, FALSE) != NULL) - { - loglog(RC_DUPNAME, "attempt to redefine connection \"%s\"", wm->name); - } - else if (wm->right.protocol != wm->left.protocol) - { - /* this should haven been diagnosed by whack - * !!! overloaded use of RC_CLASH - */ - loglog(RC_CLASH, "the protocol must be the same for leftport and rightport"); - } - else if (check_connection_end(&wm->right, &wm->left, wm) - && check_connection_end(&wm->left, &wm->right, wm)) - { - bool same_rightca, same_leftca; - connection_t *c = malloc_thing(connection_t); - - zero(c); - c->name = clone_str(wm->name); - c->ikev1 = wm->ikev1; - c->policy = wm->policy; - - if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp) - { - loglog(RC_COMMENT - , "ignoring --compress in \"%s\" because kernel does not support IPCOMP" - , c->name); - } - - if (wm->esp) - { - DBG(DBG_CONTROL, - DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp: "NULL") - ) - c->alg_info_esp = alg_info_esp_create_from_str(wm->esp? wm->esp : ""); - - DBG(DBG_CRYPT|DBG_CONTROL, - static char buf[BUF_LEN]=""; - - if (c->alg_info_esp) - { - alg_info_snprint(buf, sizeof(buf) - ,(struct alg_info *)c->alg_info_esp); - } - DBG_log("esp proposal: %s", buf); - ) - if (c->alg_info_esp) - { - if (c->alg_info_esp->alg_info_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "got 0 esp transforms"); - } - } - else - { - loglog(RC_LOG_SERIOUS, "syntax error in esp string"); - } - } - - if (wm->ike) - { - DBG(DBG_CONTROL, - DBG_log("from whack: got --ike=%s", wm->ike ? wm->ike: "NULL") - ) - c->alg_info_ike= alg_info_ike_create_from_str(wm->ike? wm->ike : ""); - - DBG(DBG_CRYPT|DBG_CONTROL, - static char buf[BUF_LEN]=""; - - if (c->alg_info_ike) - { - alg_info_snprint(buf, sizeof(buf) - , (struct alg_info *)c->alg_info_ike); - } - DBG_log("ike proposal: %s", buf); - ) - if (c->alg_info_ike) - { - if (c->alg_info_ike->alg_info_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "got 0 ike transforms"); - } - } - else - { - loglog(RC_LOG_SERIOUS, "syntax error in ike string"); - } - } - - if (wm->xauth_identity) - { - c->xauth_identity - = identification_create_from_string(wm->xauth_identity); - } - - c->sa_ike_life_seconds = wm->sa_ike_life_seconds; - c->sa_ipsec_life_seconds = wm->sa_ipsec_life_seconds; - c->sa_rekey_margin = wm->sa_rekey_margin; - c->sa_rekey_fuzz = wm->sa_rekey_fuzz; - c->sa_keying_tries = wm->sa_keying_tries; - - /* RFC 3706 DPD */ - c->dpd_delay = wm->dpd_delay; - c->dpd_timeout = wm->dpd_timeout; - c->dpd_action = wm->dpd_action; - - c->addr_family = wm->addr_family; - c->tunnel_addr_family = wm->tunnel_addr_family; - - c->requested_ca = NULL; - same_leftca = extract_end(&c->spd.this, &wm->left, wm->name, TRUE); - same_rightca = extract_end(&c->spd.that, &wm->right, wm->name, FALSE); - - if (same_rightca && c->spd.this.ca) - { - c->spd.that.ca = c->spd.this.ca->clone(c->spd.this.ca); - } - else if (same_leftca && c->spd.that.ca) - { - c->spd.this.ca = c->spd.that.ca->clone(c->spd.that.ca); - } - - default_end(&c->spd.this, &c->spd.that.host_addr); - default_end(&c->spd.that, &c->spd.this.host_addr); - - /* force any wildcard host IP address, any wildcard subnet - * or any wildcard ID to that end - */ - if (isanyaddr(&c->spd.this.host_addr) || c->spd.this.has_client_wildcard - || c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards - || c->spd.this.allow_any) - { - struct end t = c->spd.this; - - c->spd.this = c->spd.that; - c->spd.that = t; - } - - c->spd.next = NULL; - c->spd.reqid = wm->reqid ?: gen_reqid(); - - c->spd.mark_in.value = wm->mark_in.value; - c->spd.mark_in.mask = wm->mark_in.mask; - c->spd.mark_out.value = wm->mark_out.value; - c->spd.mark_out.mask = wm->mark_out.mask; - - /* set internal fields */ - c->instance_serial = 0; - c->ac_next = connections; - connections = c; - c->interface = NULL; - c->spd.routing = RT_UNROUTED; - c->newest_isakmp_sa = SOS_NOBODY; - c->newest_ipsec_sa = SOS_NOBODY; - c->spd.eroute_owner = SOS_NOBODY; - - if (c->policy & POLICY_GROUP) - { - c->kind = CK_GROUP; - add_group(c); - } - else if ((isanyaddr(&c->spd.that.host_addr) && !NEVER_NEGOTIATE(c->policy)) - || c->spd.that.has_client_wildcard || c->spd.that.has_port_wildcard - || c->spd.that.has_id_wildcards || c->spd.that.allow_any) - { - /* Opportunistic or Road Warrior or wildcard client subnet - * or wildcard ID */ - c->kind = CK_TEMPLATE; - } - else - { - c->kind = CK_PERMANENT; - } - set_policy_prio(c); /* must be after kind is set */ - -#ifdef DEBUG - c->extra_debugging = wm->debugging; -#endif - - c->gw_info = NULL; - - passert(!(wm->left.virt && wm->right.virt)); - if (wm->left.virt || wm->right.virt) - { - passert(isanyaddr(&c->spd.that.host_addr)); - c->spd.that.virt = create_virtual(c, - wm->left.virt ? wm->left.virt : wm->right.virt); - if (c->spd.that.virt) - c->spd.that.has_client = TRUE; - } - - (void)orient(c); - - /* if rightsourceip defines a subnet then create an in-memory pool */ - if (whack_attr->add_pool(whack_attr, c->name, - c->spd.this.is_left ? &wm->right : &wm->left)) - { - c->spd.that.pool = clone_str(c->name); - c->spd.that.modecfg = TRUE; - c->spd.that.has_client = FALSE; - /* reset the host_srcip so that it gets assigned in modecfg */ - DESTROY_IF(c->spd.that.host_srcip); - c->spd.that.host_srcip = host_create_any(AF_INET); - } - - if (c->ikev1) - { - connect_to_host_pair(c); - } - - /* log all about this connection */ - plog("added connection description \"%s\"", c->name); - DBG(DBG_CONTROL, - char topo[BUF_LEN]; - - (void) format_connection(topo, sizeof(topo), c, &c->spd); - - DBG_log("%s", topo); - - /* Make sure that address families can be correctly inferred - * from printed ends. - */ - passert(c->addr_family == addrtypeof(&c->spd.this.host_addr) - && c->addr_family == addrtypeof(&c->spd.this.host_nexthop) - && (c->spd.this.has_client? c->tunnel_addr_family : c->addr_family) - == subnettypeof(&c->spd.this.client) - - && c->addr_family == addrtypeof(&c->spd.that.host_addr) - && c->addr_family == addrtypeof(&c->spd.that.host_nexthop) - && (c->spd.that.has_client? c->tunnel_addr_family : c->addr_family) - == subnettypeof(&c->spd.that.client)); - - DBG_log("ike_life: %lus; ipsec_life: %lus; rekey_margin: %lus;" - " rekey_fuzz: %lu%%; keyingtries: %lu; policy: %s" - , (unsigned long) c->sa_ike_life_seconds - , (unsigned long) c->sa_ipsec_life_seconds - , (unsigned long) c->sa_rekey_margin - , (unsigned long) c->sa_rekey_fuzz - , (unsigned long) c->sa_keying_tries - , prettypolicy(c->policy)); - ); - } -} - -/* Derive a template connection from a group connection and target. - * Similar to instantiate(). Happens at whack --listen. - * Returns name of new connection. May be NULL. - * Caller is responsible for freeing. - */ -char *add_group_instance(connection_t *group, const ip_subnet *target) -{ - char namebuf[100], targetbuf[SUBNETTOT_BUF]; - connection_t *t; - char *name = NULL; - - passert(group->kind == CK_GROUP); - passert(oriented(*group)); - - /* manufacture a unique name for this template */ - subnettot(target, 0, targetbuf, sizeof(targetbuf)); - snprintf(namebuf, sizeof(namebuf), "%s#%s", group->name, targetbuf); - - if (con_by_name(namebuf, FALSE) != NULL) - { - loglog(RC_DUPNAME, "group name + target yields duplicate name \"%s\"" - , namebuf); - } - else - { - t = clone_thing(*group); - t->name = namebuf; - unshare_connection_strings(t); - name = clone_str(t->name); - t->spd.that.client = *target; - t->policy &= ~(POLICY_GROUP | POLICY_GROUTED); - t->kind = isanyaddr(&t->spd.that.host_addr) && !NEVER_NEGOTIATE(t->policy) - ? CK_TEMPLATE : CK_INSTANCE; - - /* reset log file info */ - t->log_file_name = NULL; - t->log_file = NULL; - t->log_file_err = FALSE; - - t->spd.reqid = gen_reqid(); - - if (t->spd.that.virt) - { - DBG_log("virtual_ip not supported in group instance"); - t->spd.that.virt = NULL; - } - - /* add to connections list */ - t->ac_next = connections; - connections = t; - - /* same host_pair as parent: stick after parent on list */ - group->hp_next = t; - - /* route if group is routed */ - if (group->policy & POLICY_GROUTED) - { - if (!trap_connection(t)) - whack_log(RC_ROUTE, "could not route"); - } - } - return name; -} - -/* an old target has disappeared for a group: delete instance */ -void remove_group_instance(const connection_t *group USED_BY_DEBUG, - const char *name) -{ - passert(group->kind == CK_GROUP); - passert(oriented(*group)); - - delete_connections_by_name(name, FALSE); -} - -/* Common part of instantiating a Road Warrior or Opportunistic connection. - * his_id can be used to carry over an ID discovered in Phase 1. - * It must not disagree with the one in c, but if that is unspecified, - * the new connection will use his_id. - * If his_id is NULL, and c.that.id is uninstantiated (ID_ANY), the - * new connection will continue to have an uninstantiated that.id. - * Note: instantiation does not affect port numbers. - * - * Note that instantiate can only deal with a single SPD/eroute. - */ -static connection_t *instantiate(connection_t *c, const ip_address *him, - u_int16_t his_port, identification_t *his_id) -{ - connection_t *d; - - passert(c->kind == CK_TEMPLATE); - passert(c->spd.next == NULL); - - c->instance_serial++; - d = clone_thing(*c); - d->spd.that.allow_any = FALSE; - - if (his_id) - { - d->spd.that.id = his_id; - d->spd.that.has_id_wildcards = FALSE; - } - unshare_connection_strings(d); - if (d->spd.this.groups) - { - d->spd.this.groups = d->spd.this.groups->get_ref(d->spd.this.groups); - } - if (d->spd.that.groups) - { - d->spd.that.groups = d->spd.that.groups->get_ref(d->spd.that.groups); - } - d->kind = CK_INSTANCE; - - passert(oriented(*d)); - d->spd.that.host_addr = *him; - setportof(htons(c->spd.that.port), &d->spd.that.host_addr); - - if (his_port) d->spd.that.host_port = his_port; - - default_end(&d->spd.that, &d->spd.this.host_addr); - - /* We cannot guess what our next_hop should be, but if it was - * explicitly specified as 0.0.0.0, we set it to be him. - * (whack will not allow nexthop to be elided in RW case.) - */ - default_end(&d->spd.this, &d->spd.that.host_addr); - d->spd.next = NULL; - d->spd.reqid = gen_reqid(); - - /* set internal fields */ - d->ac_next = connections; - connections = d; - d->spd.routing = RT_UNROUTED; - d->newest_isakmp_sa = SOS_NOBODY; - d->newest_ipsec_sa = SOS_NOBODY; - d->spd.eroute_owner = SOS_NOBODY; - - /* reset log file info */ - d->log_file_name = NULL; - d->log_file = NULL; - d->log_file_err = FALSE; - - connect_to_host_pair(d); - - if (sameaddr(&d->spd.that.host_addr, &d->spd.this.host_nexthop)) - { - d->spd.this.host_nexthop = *him; - } - return d; -} - -connection_t *rw_instantiate(connection_t *c, const ip_address *him, - u_int16_t his_port, const ip_subnet *his_net, - identification_t *his_id) -{ - connection_t *d = instantiate(c, him, his_port, his_id); - - if (d && his_net && is_virtual_connection(c)) - { - d->spd.that.client = *his_net; - d->spd.that.virt = NULL; - if (subnetishost(his_net) && addrinsubnet(him, his_net)) - d->spd.that.has_client = FALSE; - } - - if (d->policy & POLICY_OPPO) - { - /* This must be before we know the client addresses. - * Fill in one that is impossible. This prevents anyone else from - * trying to use this connection to get to a particular client - */ - d->spd.that.client = *aftoinfo(subnettypeof(&d->spd.that.client))->none; - } - DBG(DBG_CONTROL - , DBG_log("instantiated \"%s\" for %s" , d->name, ip_str(him))); - return d; -} - -#ifdef ADNS - -connection_t *oppo_instantiate(connection_t *c, const ip_address *him, - identification_t *his_id, struct gw_info *gw, - const ip_address *our_client USED_BY_DEBUG, - const ip_address *peer_client) -{ - connection_t *d = instantiate(c, him, 0, his_id); - - passert(d->spd.next == NULL); - - /* fill in our client side */ - if (d->spd.this.has_client) - { - /* there was a client in the abstract connection - * so we demand that the required client is within that subnet. - */ - passert(addrinsubnet(our_client, &d->spd.this.client)); - happy(addrtosubnet(our_client, &d->spd.this.client)); - /* opportunistic connections do not use port selectors */ - setportof(0, &d->spd.this.client.addr); - } - else - { - /* there was no client in the abstract connection - * so we demand that the required client be the host - */ - passert(sameaddr(our_client, &d->spd.this.host_addr)); - } - - /* fill in peer's client side. - * If the client is the peer, excise the client from the connection. - */ - passert((d->policy & POLICY_OPPO) - && addrinsubnet(peer_client, &d->spd.that.client)); - happy(addrtosubnet(peer_client, &d->spd.that.client)); - /* opportunistic connections do not use port selectors */ - setportof(0, &d->spd.that.client.addr); - - if (sameaddr(peer_client, &d->spd.that.host_addr)) - d->spd.that.has_client = FALSE; - - passert(d->gw_info == NULL); - gw_addref(gw); - d->gw_info = gw; - - /* Adjust routing if something is eclipsing c. - * It must be a %hold for us (hard to passert this). - * If there was another instance eclipsing, we'd be using it. - */ - if (c->spd.routing == RT_ROUTED_ECLIPSED) - d->spd.routing = RT_ROUTED_PROSPECTIVE; - - /* Remember if the template is routed: - * if so, this instance applies for initiation - * even if it is created for responding. - */ - if (routed(c->spd.routing)) - d->instance_initiation_ok = TRUE; - - DBG(DBG_CONTROL, - char topo[BUF_LEN]; - - (void) format_connection(topo, sizeof(topo), d, &d->spd); - DBG_log("instantiated \"%s\": %s", d->name, topo); - ); - return d; -} - -#endif /* ADNS */ - -/* priority formatting */ -void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) -{ - if (pp == BOTTOM_PRIO) - { - snprintf(buf, POLICY_PRIO_BUF, "0"); - } - else - { - snprintf(buf, POLICY_PRIO_BUF, "%lu,%lu" - , pp>>16, (pp & ~(~(policy_prio_t)0 << 16)) >> 8); - } -} - -/* Format any information needed to identify an instance of a connection. - * Fills any needed information into buf which MUST be big enough. - * Road Warrior: peer's IP address - * Opportunistic: [" " myclient "==="] " ..." peer ["===" hisclient] '\0' - */ -static size_t fmt_client(const ip_subnet *client, const ip_address *gw, - const char *prefix, char buf[ADDRTOT_BUF]) -{ - if (subnetisaddr(client, gw)) - { - buf[0] = '\0'; /* compact denotation for "self" */ - } - else - { - char *ap; - - strcpy(buf, prefix); - ap = buf + strlen(prefix); - if (subnetisnone(client)) - strcpy(ap, "?"); /* unknown */ - else - subnettot(client, 0, ap, SUBNETTOT_BUF); - } - return strlen(buf); -} - -void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]) -{ - char *p = buf; - - *p = '\0'; - - if (c->kind == CK_INSTANCE) - { - if (c->instance_serial != 0) - { - snprintf(p, CONN_INST_BUF, "[%lu]", c->instance_serial); - p += strlen(p); - } - - if (c->policy & POLICY_OPPO) - { - size_t w = fmt_client(&c->spd.this.client, &c->spd.this.host_addr, " ", p); - - p += w; - - strcpy(p, w == 0? " ..." : "=== ..."); - p += strlen(p); - - addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); - p += strlen(p); - - (void) fmt_client(&c->spd.that.client, &c->spd.that.host_addr, "===", p); - } - else - { - *p++ = ' '; - addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); -# - if (c->spd.that.host_port != pluto_port) - { - p += strlen(p); - sprintf(p, ":%d", c->spd.that.host_port); - } - } - } -} - -/* Find an existing connection for a trapped outbound packet. - * This is attempted before we bother with gateway discovery. - * + this connection is routed or instance_of_routed_template - * (i.e. approved for on-demand) - * + this subnet contains our_client (or we are our_client) - * + that subnet contains peer_client (or peer is peer_client) - * + don't care about Phase 1 IDs (we don't know) - * Note: result may still need to be instantiated. - * The winner has the highest policy priority. - * - * If there are several with that priority, we give preference to - * the first one that is an instance. - * - * See also build_outgoing_opportunistic_connection. - */ -connection_t *find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto) -{ - connection_t *c = connections, *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - struct spd_route *sr; - struct spd_route *best_sr = NULL; - int our_port = ntohs(portof(our_client)); - int peer_port = ntohs(portof(peer_client)); - - passert(!isanyaddr(our_client) && !isanyaddr(peer_client)); -#ifdef DEBUG - if (DBGP(DBG_CONTROL)) - { - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(our_client, 0, ocb, sizeof(ocb)); - addrtot(peer_client, 0, pcb, sizeof(pcb)); - DBG_log("find_connection: " - "looking for policy for connection: %s:%d/%d -> %s:%d/%d" - , ocb, transport_proto, our_port, pcb, transport_proto, peer_port); - } -#endif /* DEBUG */ - - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->kind == CK_GROUP) - { - continue; - } - - for (sr = &c->spd; best!=c && sr; sr = sr->next) - { - if ((routed(sr->routing) || c->instance_initiation_ok) - && addrinsubnet(our_client, &sr->this.client) - && addrinsubnet(peer_client, &sr->that.client) - && addrinsubnet(peer_client, &sr->that.client) - && (!sr->this.protocol || transport_proto == sr->this.protocol) - && (!sr->this.port || our_port == sr->this.port) - && (!sr->that.port || peer_port == sr->that.port)) - { - char cib[CONN_INST_BUF]; - char cib2[CONN_INST_BUF]; - - policy_prio_t prio = 8 * (c->prio + (c->kind == CK_INSTANCE)) - + 2 * (sr->this.port == our_port) - + 2 * (sr->that.port == peer_port) - + (sr->this.protocol == transport_proto); - -#ifdef DEBUG - if (DBGP(DBG_CONTROL|DBG_CONTROLMORE)) - { - char c_ocb[SUBNETTOT_BUF], c_pcb[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, c_ocb, sizeof(c_ocb)); - subnettot(&c->spd.that.client, 0, c_pcb, sizeof(c_pcb)); - DBG_log("find_connection: conn \"%s\"%s has compatible peers: %s->%s [pri: %ld]" - , c->name - , (fmt_conn_instance(c, cib), cib) - , c_ocb, c_pcb, prio); - } -#endif /* DEBUG */ - - if (best == NULL) - { - best = c; - best_sr = sr; - best_prio = prio; - } - - DBG(DBG_CONTROLMORE, - DBG_log("find_connection: " - "comparing best \"%s\"%s [pri:%ld]{%p} (child %s) to \"%s\"%s [pri:%ld]{%p} (child %s)" - , best->name - , (fmt_conn_instance(best, cib), cib) - , best_prio - , best - , (best->policy_next ? best->policy_next->name : "none") - , c->name - , (fmt_conn_instance(c, cib2), cib2) - , prio - , c - , (c->policy_next ? c->policy_next->name : "none"))); - - if (prio > best_prio) - { - best = c; - best_sr = sr; - best_prio = prio; - } - } - } - } - - if (best && NEVER_NEGOTIATE(best->policy)) - { - best = NULL; - } - if (srp && best) - { - *srp = best_sr; - } - -#ifdef DEBUG - if (DBGP(DBG_CONTROL)) - { - if (best) - { - char cib[CONN_INST_BUF]; - DBG_log("find_connection: concluding with \"%s\"%s [pri:%ld]{%p} kind=%s" - , best->name - , (fmt_conn_instance(best, cib), cib) - , best_prio - , best - , enum_name(&connection_kind_names, best->kind)); - } else { - DBG_log("find_connection: concluding with empty"); - } - } -#endif /* DEBUG */ - - return best; -} - -#ifdef ADNS - -/* Find and instantiate a connection for an outgoing Opportunistic connection. - * We've already discovered its gateway. - * We look for a the connection such that: - * + this is one of our interfaces - * + this subnet contains our_client (or we are our_client) - * (we will specialize the client). We prefer the smallest such subnet. - * + that subnet contains peer_clent (we will specialize the client). - * We prefer the smallest such subnet. - * + is opportunistic - * + that peer is NO_IP - * + don't care about Phase 1 IDs (probably should be default) - * We could look for a connection that already had the desired peer - * (rather than NO_IP) specified, but it doesn't seem worth the - * bother. - * - * We look for the routed policy applying to the narrowest subnets. - * We only succeed if we find such a policy AND it is satisfactory. - * - * The body of the inner loop is a lot like that in - * find_connection_for_clients. In this case, we know the gateways - * that we need to instantiate an opportunistic connection. - */ -connection_t *build_outgoing_opportunistic_connection(struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client) -{ - struct iface *p; - connection_t *best = NULL; - struct spd_route *sr, *bestsr; - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(our_client, 0, ocb, sizeof(ocb)); - addrtot(peer_client, 0, pcb, sizeof(pcb)); - - /* for each of our addresses... */ - for (p = interfaces; p != NULL; p = p->next) - { - /* go through those connections with our address and NO_IP as hosts - * We cannot know what port the peer would use, so we assume - * that it is pluto_port (makes debugging easier). - */ - connection_t *c = find_host_pair_connections(&p->addr, pluto_port, - (ip_address *)NULL, pluto_port); - - for (; c != NULL; c = c->hp_next) - { - DBG(DBG_OPPO, - DBG_log("checking %s", c->name)); - if (c->kind == CK_GROUP) - { - continue; - } - - for (sr = &c->spd; best!=c && sr; sr = sr->next) - { - if (routed(sr->routing) - && addrinsubnet(our_client, &sr->this.client) - && addrinsubnet(peer_client, &sr->that.client)) - { - if (best == NULL) - { - best = c; - break; - } - - DBG(DBG_OPPO, - DBG_log("comparing best %s to %s" - , best->name, c->name)); - - for (bestsr = &best->spd; best!=c && bestsr; bestsr=bestsr->next) - { - if (!subnetinsubnet(&bestsr->this.client, &sr->this.client) - || (samesubnet(&bestsr->this.client, &sr->this.client) - && !subnetinsubnet(&bestsr->that.client - , &sr->that.client))) - { - best = c; - } - } - } - } - } - } - - if (best == NULL || NEVER_NEGOTIATE(best->policy) || - (best->policy & POLICY_OPPO) == LEMPTY || best->kind != CK_TEMPLATE) - { - return NULL; - } - else - { - chunk_t encoding = gw->gw_id->get_encoding(gw->gw_id); - id_type_t type = gw->gw_id->get_type(gw->gw_id); - ip_address ip_addr; - - initaddr(encoding.ptr, encoding.len, - (type == ID_IPV4_ADDR) ? AF_INET : AF_INET6, &ip_addr); - - return oppo_instantiate(best, &ip_addr, NULL, gw, our_client, peer_client); - } -} - -#endif /* ADNS */ - -bool orient(connection_t *c) -{ - struct spd_route *sr; - - if (!oriented(*c)) - { - struct iface *p; - - for (sr = &c->spd; sr; sr = sr->next) - { - /* Note: this loop does not stop when it finds a match: - * it continues checking to catch any ambiguity. - */ - for (p = interfaces; p != NULL; p = p->next) - { - if (p->ike_float) - { - continue; - } - - for (;;) - { - /* check if this interface matches this end */ - if (sameaddr(&sr->this.host_addr, &p->addr) - && sr->this.host_port == pluto_port) - { - if (oriented(*c)) - { - if (c->interface == p) - loglog(RC_LOG_SERIOUS - , "both sides of \"%s\" are our interface %s!" - , c->name, p->rname); - else - loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)" - , c->name, c->interface->rname, p->rname); - c->interface = NULL; /* withdraw orientation */ - return FALSE; - } - c->interface = p; - } - - /* done with this interface if it doesn't match that end */ - if (!(sameaddr(&sr->that.host_addr, &p->addr) - && sr->that.host_port == pluto_port)) - break; - - /* swap ends and try again. - * It is a little tricky to see that this loop will stop. - * Only continue if the far side matches. - * If both sides match, there is an error-out. - */ - { - struct end t = sr->this; - - sr->this = sr->that; - sr->that = t; - } - } - } - } - } - return oriented(*c); -} - -void initiate_connection(const char *name, int whackfd) -{ - connection_t *c = con_by_name(name, TRUE); - - if (c && c->ikev1) - { - set_cur_connection(c); - if (!oriented(*c)) - { - loglog(RC_ORIENT, "we have no ipsecN interface for either end of this connection"); - } - else if (NEVER_NEGOTIATE(c->policy)) - { - loglog(RC_INITSHUNT - , "cannot initiate an authby=never connection"); - } - else if (c->kind != CK_PERMANENT && !c->spd.that.allow_any) - { - if (isanyaddr(&c->spd.that.host_addr)) - loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address"); - else - loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards"); - } - else - { - /* do we have to prompt for a PIN code? */ - if (c->spd.this.sc && !c->spd.this.sc->valid && whackfd != NULL_FD) - { - scx_get_pin(c->spd.this.sc, whackfd); - } - if (c->spd.this.sc && !c->spd.this.sc->valid) - { - loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN"); - } - else - { - - if (c->spd.that.allow_any) - { - c = instantiate(c, &c->spd.that.host_addr, - c->spd.that.host_port, c->spd.that.id); - } - - /* We will only request an IPsec SA if policy isn't empty - * (ignoring Main Mode items). - * This is a fudge, but not yet important. - * If we are to proceed asynchronously, whackfd will be NULL_FD. - */ - c->policy |= POLICY_UP; - ipsecdoi_initiate(whackfd, c, c->policy, 1, SOS_NOBODY); - whackfd = NULL_FD; /* protect from close */ - } - } - reset_cur_connection(); - } - close_any(whackfd); -} - -/* (Possibly) Opportunistic Initiation: - * Knowing clients (single IP addresses), try to build an tunnel. - * This may involve discovering a gateway and instantiating an - * Opportunistic connection. Called when a packet is caught by - * a %trap, or when whack --oppohere --oppothere is used. - * It may turn out that an existing or non-opporunistic connnection - * can handle the traffic. - * - * Most of the code will be restarted if an ADNS request is made - * to discover the gateway. The only difference between the first - * and second entry is whether gateways_from_dns is NULL or not. - * initiate_opportunistic: initial entrypoint - * continue_oppo: where we pickup when ADNS result arrives - * initiate_opportunistic_body: main body shared by above routines - * cannot_oppo: a helper function to log a diagnostic - * This structure repeats a lot of code when the ADNS result arrives. - * This seems like a waste, but anything learned the first time through - * may no longer be true! - * - * After the first IKE message is sent, the regular state machinery - * carries negotiation forward. - */ - -enum find_oppo_step { - fos_start, - fos_myid_ip_txt, - fos_myid_hostname_txt, - fos_myid_ip_key, - fos_myid_hostname_key, - fos_our_client, - fos_our_txt, -#ifdef USE_KEYRR - fos_our_key, -#endif /* USE_KEYRR */ - fos_his_client, - fos_done -}; - -#ifdef DEBUG -static const char *const oppo_step_name[] = { - "fos_start", - "fos_myid_ip_txt", - "fos_myid_hostname_txt", - "fos_myid_ip_key", - "fos_myid_hostname_key", - "fos_our_client", - "fos_our_txt", -#ifdef USE_KEYRR - "fos_our_key", -#endif /* USE_KEYRR */ - "fos_his_client", - "fos_done" -}; -#endif /* DEBUG */ - -struct find_oppo_bundle { - enum find_oppo_step step; - err_t want; - bool failure_ok; /* if true, continue_oppo should not die on DNS failure */ - ip_address our_client; /* not pointer! */ - ip_address peer_client; - int transport_proto; - bool held; - policy_prio_t policy_prio; - ipsec_spi_t failure_shunt; /* in host order! 0 for delete. */ - int whackfd; -}; - -struct find_oppo_continuation { - struct adns_continuation ac; /* common prefix */ - struct find_oppo_bundle b; -}; - -static void cannot_oppo(connection_t *c, struct find_oppo_bundle *b, err_t ugh) -{ - char pcb[ADDRTOT_BUF]; - char ocb[ADDRTOT_BUF]; - - addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); - addrtot(&b->our_client, 0, ocb, sizeof(ocb)); - - DBG(DBG_DNS | DBG_OPPO, DBG_log("Can't Opportunistically initiate for %s to %s: %s" - , ocb, pcb, ugh)); - - whack_log(RC_OPPOFAILURE - , "Can't Opportunistically initiate for %s to %s: %s" - , ocb, pcb, ugh); - - if (c && c->policy_next) - { - /* there is some policy that comes afterwards */ - struct spd_route *shunt_spd; - connection_t *nc = c->policy_next; - struct state *st; - - passert(c->kind == CK_TEMPLATE); - passert(c->policy_next->kind == CK_PERMANENT); - - DBG(DBG_OPPO, DBG_log("OE failed for %s to %s, but %s overrides shunt" - , ocb, pcb, c->policy_next->name)); - - /* - * okay, here we need add to the "next" policy, which is ought - * to be an instance. - * We will add another entry to the spd_route list for the specific - * situation that we have. - */ - - shunt_spd = clone_thing(nc->spd); - - shunt_spd->next = nc->spd.next; - nc->spd.next = shunt_spd; - - happy(addrtosubnet(&b->peer_client, &shunt_spd->that.client)); - - if (sameaddr(&b->peer_client, &shunt_spd->that.host_addr)) - shunt_spd->that.has_client = FALSE; - - /* - * override the tunnel destination with the one from the secondaried - * policy - */ - shunt_spd->that.host_addr = nc->spd.that.host_addr; - - /* now, lookup the state, and poke it up. - */ - - st = state_with_serialno(nc->newest_ipsec_sa); - - /* XXX what to do if the IPSEC SA has died? */ - passert(st != NULL); - - /* link the new connection instance to the state's list of - * connections - */ - - DBG(DBG_OPPO, DBG_log("installing state: %ld for %s to %s" - , nc->newest_ipsec_sa - , ocb, pcb)); - -#ifdef DEBUG - if (DBGP(DBG_OPPO | DBG_CONTROLMORE)) - { - char state_buf[LOG_WIDTH]; - char state_buf2[LOG_WIDTH]; - time_t n = now(); - - fmt_state(FALSE, st, n - , state_buf, sizeof(state_buf) - , state_buf2, sizeof(state_buf2)); - DBG_log("cannot_oppo, failure SA1: %s", state_buf); - DBG_log("cannot_oppo, failure SA2: %s", state_buf2); - } -#endif /* DEBUG */ - - if (!route_and_eroute(c, shunt_spd, st)) - { - whack_log(RC_OPPOFAILURE - , "failed to instantiate shunt policy %s for %s to %s" - , c->name - , ocb, pcb); - } - return; - } -} - -static void initiate_opportunistic_body(struct find_oppo_bundle *b - , struct adns_continuation *ac, err_t ac_ugh); /* forward */ - -void initiate_opportunistic(const ip_address *our_client, - const ip_address *peer_client, int transport_proto, - bool held, int whackfd) -{ - struct find_oppo_bundle b; - - b.want = (whackfd == NULL_FD ? "whack" : "acquire"); - b.failure_ok = FALSE; - b.our_client = *our_client; - b.peer_client = *peer_client; - b.transport_proto = transport_proto; - b.held = held; - b.policy_prio = BOTTOM_PRIO; - b.failure_shunt = 0; - b.whackfd = whackfd; - b.step = fos_start; - initiate_opportunistic_body(&b, NULL, NULL); -} - -#ifdef ADNS - -static void continue_oppo(struct adns_continuation *acr, err_t ugh) -{ - struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */ - connection_t *c; - bool was_held = cr->b.held; - int whackfd = cr->b.whackfd; - - /* note: cr->id has no resources; cr->sgw_id is ID_ANY: - * neither need freeing. - */ - whack_log_fd = whackfd; - -#ifdef DEBUG - /* if we're going to ignore the error, at least note it in debugging log */ - if (cr->b.failure_ok && ugh) - { - DBG(DBG_CONTROL | DBG_DNS, - { - char ocb[ADDRTOT_BUF]; - char pcb[ADDRTOT_BUF]; - - addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb)); - addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb)); - DBG_log("continuing from failed DNS lookup for %s, %s to %s: %s" - , cr->b.want, ocb, pcb, ugh); - }); - } -#endif - - if (!cr->b.failure_ok && ugh) - { - c = find_connection_for_clients(NULL, &cr->b.our_client, &cr->b.peer_client - , cr->b.transport_proto); - cannot_oppo(c, &cr->b - , builddiag("%s: %s", cr->b.want, ugh)); - } - else if (was_held && !cr->b.held) - { - /* was_held indicates we were started due to a %trap firing - * (as opposed to a "whack --oppohere --oppothere"). - * Since the %hold has gone, we can assume that somebody else - * has beaten us to the punch. We can go home. But lets log it. - */ - char ocb[ADDRTOT_BUF]; - char pcb[ADDRTOT_BUF]; - - addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb)); - addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb)); - - loglog(RC_COMMENT - , "%%hold otherwise handled during DNS lookup for Opportunistic Initiation for %s to %s" - , ocb, pcb); - } - else - { - initiate_opportunistic_body(&cr->b, &cr->ac, ugh); - whackfd = NULL_FD; /* was handed off */ - } - - whack_log_fd = NULL_FD; - close_any(whackfd); -} - -#endif /* ADNS */ - -#ifdef USE_KEYRR -static err_t check_key_recs(enum myid_state try_state, const connection_t *c, - struct adns_continuation *ac) -{ - /* Check if KEY lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - enum myid_state old_myid_state = myid_state; - private_key_t *private; - err_t ugh = NULL; - - myid_state = try_state; - - if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED) - { - ugh = "%myid was specified while we were guessing"; - } - else if ((private = get_private_key(c)) == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!same_id(&ac->id, &c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - pubkey_list_t *kr; - - ugh = "no KEY RR found for us"; - for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next) - { - ugh = "all our KEY RRs have the wrong public key"; - if (kr->key->alg == PUBKEY_ALG_RSA - && private->belongs_to(private, &kr->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - if (ugh) - { - myid_state = old_myid_state; - } - return ugh; -} -#endif /* USE_KEYRR */ - -#ifdef ADNS - -static err_t check_txt_recs(enum myid_state try_state, const connection_t *c, - struct adns_continuation *ac) -{ - /* Check if TXT lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - enum myid_state old_myid_state = myid_state; - private_key_t *private; - err_t ugh = NULL; - - myid_state = try_state; - - if (old_myid_state != myid_state - && old_myid_state == MYID_SPECIFIED) - { - ugh = "%myid was specified while we were guessing"; - } - else if ((private = get_private_key(c)) == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!ac->id->equals(ac->id, c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR found for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - public_key_t *pub_key = gwp->key->public_key; - - ugh = "all our TXT RRs have the wrong public key"; - if (pub_key->get_type(pub_key) == KEY_RSA && - private->belongs_to(private, pub_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - if (ugh) - { - myid_state = old_myid_state; - } - return ugh; -} - -#endif /* ADNS */ - - -/* note: gateways_from_dns must be NULL iff this is the first call */ -static void initiate_opportunistic_body(struct find_oppo_bundle *b, - struct adns_continuation *ac, - err_t ac_ugh) -{ - connection_t *c; - struct spd_route *sr; - - /* What connection shall we use? - * First try for one that explicitly handles the clients. - */ - DBG(DBG_CONTROL, - { - char ours[ADDRTOT_BUF]; - char his[ADDRTOT_BUF]; - int ourport; - int hisport; - - addrtot(&b->our_client, 0, ours, sizeof(ours)); - addrtot(&b->peer_client, 0, his, sizeof(his)); - ourport = ntohs(portof(&b->our_client)); - hisport = ntohs(portof(&b->peer_client)); - DBG_log("initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s" - , ours, ourport, his, hisport, b->transport_proto - , oppo_step_name[b->step], b->want); - }); - if (isanyaddr(&b->our_client) || isanyaddr(&b->peer_client)) - { - cannot_oppo(NULL, b, "impossible IP address"); - } - else if ((c = find_connection_for_clients(&sr - , &b->our_client - , &b->peer_client - , b->transport_proto)) == NULL) - { - /* No connection explicitly handles the clients and there - * are no Opportunistic connections -- whine and give up. - * The failure policy cannot be gotten from a connection; we pick %pass. - */ - cannot_oppo(NULL, b, "no routed Opportunistic template covers this pair"); - } - else if (c->kind != CK_TEMPLATE) - { - /* We've found a connection that can serve. - * Do we have to initiate it? - * Not if there is currently an IPSEC SA. - * But if there is an IPSEC SA, then the kernel would not - * have generated the acquire. So we assume that there isn't one. - * This may be redundant if a non-opportunistic - * negotiation is already being attempted. - */ - - /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ - - if(c->kind == CK_INSTANCE) - { - char cib[CONN_INST_BUF]; - /* there is already an instance being negotiated, no nothing */ - DBG(DBG_CONTROL, DBG_log("found existing instance \"%s\"%s, rekeying it" - , c->name - , (fmt_conn_instance(c, cib), cib))); - /* XXX-mcr - return; */ - } - - /* otherwise, there is some kind of static conn that can handle - * this connection, so we initiate it */ - - if (b->held) - { - /* what should we do on failure? */ - (void) assign_hold(c, sr, b->transport_proto, &b->our_client, &b->peer_client); - } - ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); - b->whackfd = NULL_FD; /* protect from close */ - } -#ifdef ADNS - else - { - /* We are handling an opportunistic situation. - * This involves several DNS lookup steps that require suspension. - * Note: many facts might change while we're suspended. - * Here be dragons. - * - * The first chunk of code handles the result of the previous - * DNS query (if any). It also selects the kind of the next step. - * The second chunk initiates the next DNS query (if any). - */ - enum find_oppo_step next_step = fos_myid_ip_txt; - err_t ugh = ac_ugh; - char mycredentialstr[BUF_LEN]; - char cib[CONN_INST_BUF]; - - DBG(DBG_CONTROL, DBG_log("creating new instance from \"%s\"%s", - c->name, (fmt_conn_instance(c, cib), cib))); - snprintf(mycredentialstr, BUF_LEN, "%Y", sr->this.id); - - /* handle any DNS answer; select next step */ - switch (b->step) - { - case fos_start: - /* just starting out: select first query step */ - next_step = fos_myid_ip_txt; - break; - - case fos_myid_ip_txt: /* TXT for our default IP address as %myid */ - ugh = check_txt_recs(MYID_IP, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our IP (%Y:TXT) as identity: %s", - myids[MYID_IP], ugh)); - if (!logged_myid_ip_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our IP (%Y:TXT) as identity: %s", - myids[MYID_IP], ugh); - logged_myid_ip_txt_warning = TRUE; - } - - next_step = fos_myid_hostname_txt; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_ip_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "using our IP (%Y:TXT) as identity!", - myids[MYID_IP]); - logged_myid_ip_txt_warning = TRUE; - } - - next_step = fos_our_client; - } - break; - - case fos_myid_hostname_txt: /* TXT for our hostname as %myid */ - ugh = check_txt_recs(MYID_HOSTNAME, c, ac); - if (ugh) - { - /* cannot use our hostname as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our hostname (%Y:TXT) as identity: %s", - myids[MYID_HOSTNAME], ugh)); - if (!logged_myid_fqdn_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our hostname (%Y:TXT) as identity: %s", - myids[MYID_HOSTNAME], ugh); - logged_myid_fqdn_txt_warning = TRUE; - } -#ifdef USE_KEYRR - next_step = fos_myid_ip_key; - ugh = NULL; /* failure can be recovered from */ -#endif - } - else - { - /* we can use our hostname as OE identity for initiation */ - if (!logged_myid_fqdn_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "using our hostname (%Y:TXT) as identity!", - myids[MYID_HOSTNAME]); - logged_myid_fqdn_txt_warning = TRUE; - } - next_step = fos_our_client; - } - break; - -#ifdef USE_KEYRR - case fos_myid_ip_key: /* KEY for our default IP address as %myid */ - ugh = check_key_recs(MYID_IP, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our IP (%Y:KEY) as identity: %s", - myids[MYID_IP], ugh)); - if (!logged_myid_ip_key_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our IP (%Y:KEY) as identity: %s", - myids[MYID_IP], ugh); - logged_myid_ip_key_warning = TRUE; - } - - next_step = fos_myid_hostname_key; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_ip_key_warning) - { - loglog(RC_LOG_SERIOUS, - "using our IP (%Y:KEY) as identity!", - myids[MYID_IP]); - logged_myid_ip_key_warning = TRUE; - } - next_step = fos_our_client; - } - break; - - case fos_myid_hostname_key: /* KEY for our hostname as %myid */ - ugh = check_key_recs(MYID_HOSTNAME, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our hostname (%Y:KEY) as identity: %s", - myids[MYID_HOSTNAME], ugh)); - if (!logged_myid_fqdn_key_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our hostname (%Y:KEY) as identity: %s", - myids[MYID_HOSTNAME], ugh); - logged_myid_fqdn_key_warning = TRUE; - } - next_step = fos_myid_hostname_key; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_fqdn_key_warning) - { - loglog(RC_LOG_SERIOUS, - "using our hostname (%Y:KEY) as identity!", - myids[MYID_HOSTNAME]); - logged_myid_fqdn_key_warning = TRUE; - } - next_step = fos_our_client; - } - break; -#endif - - case fos_our_client: /* TXT for our client */ - { - /* Our client is not us: we must check the TXT records. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* normal situation */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (sameaddr(&sr->this.host_addr, &b->our_client)) - { - /* this wasn't true when we started -- bail */ - ugh = "our IP address changed underfoot"; - } - else if (!ac->sgw_id->equals(ac->sgw_id, sr->this.id)) - { - /* this wasn't true when we started -- bail */ - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in quick_inI1_outR1_tail - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR for our client delegates us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "TXT RR for our client has wrong key"; - /* If there is a key from the TXT record, - * we count it as a win if we match the key. - * If there was no key, we have a tentative win: - * we need to check our KEY record to be sure. - */ - if (!gwp->gw_key_present) - { - /* Success, but the TXT had no key - * so we must check our our own KEY records. - */ - next_step = fos_our_txt; - ugh = NULL; /* good! */ - break; - } - if (private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - } - break; - - case fos_our_txt: /* TXT for us */ - { - /* Check if TXT lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* unless we decide to look for KEY RR */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!ac->id->equals(ac->id, c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "TXT RR for us has wrong key"; - if (gwp->gw_key_present && - private->belongs_to(private, gwp->key->public_key)) - { - DBG(DBG_CONTROL, - DBG_log("initiate on demand found TXT with right public key at: %s" - , mycredentialstr)); - ugh = NULL; - break; - } - } -#ifdef USE_KEYRR - if (ugh) - { - /* if no TXT with right key, try KEY */ - DBG(DBG_CONTROL, - DBG_log("will try for KEY RR since initiate on demand found %s: %s" - , ugh, mycredentialstr)); - next_step = fos_our_key; - ugh = NULL; - } -#endif - } - } - break; - -#ifdef USE_KEYRR - case fos_our_key: /* KEY for us */ - { - /* Check if KEY lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* always */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!same_id(&ac->id, &c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - pubkey_list_t *kr; - - ugh = "no KEY RR found for us (and no good TXT RR)"; - for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next) - { - ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)"; - if (kr->key->alg == PUBKEY_ALG_RSA - && private->belongs_to(private, kr->key->public_key)) - { - /* do this only once a day */ - if (!logged_txt_warning) - { - loglog(RC_LOG_SERIOUS - , "found KEY RR but not TXT RR for %s. See http://www.freeswan.org/err/txt-change.html." - , mycredentialstr); - logged_txt_warning = TRUE; - } - ugh = NULL; /* good! */ - break; - } - } - } - } - break; -#endif /* USE_KEYRR */ - - case fos_his_client: /* TXT for his client */ - { - /* We've finished last DNS queries: TXT for his client. - * Using the information, try to instantiate a connection - * and start negotiating. - * We now know the peer. The chosing of "c" ignored this, - * so we will disregard its current value. - * !!! We need to randomize the entry in gw that we choose. - */ - next_step = fos_done; /* no more queries */ - - c = build_outgoing_opportunistic_connection(ac->gateways_from_dns - , &b->our_client - , &b->peer_client); - - if (c == NULL) - { - /* We cannot seem to instantiate a suitable connection: - * complain clearly. - */ - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(&b->our_client, 0, ocb, sizeof(ocb)); - addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); - loglog(RC_OPPOFAILURE, - "no suitable connection for opportunism " - "between %s and %s with %Y as peer", - ocb, pcb, ac->gateways_from_dns->gw_id); - } - else - { - /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ - passert(c->kind == CK_INSTANCE); - passert(c->gw_info != NULL); - passert(HAS_IPSEC_POLICY(c->policy)); - passert(LHAS(LELEM(RT_UNROUTED) | LELEM(RT_ROUTED_PROSPECTIVE), c->spd.routing)); - if (b->held) - { - /* what should we do on failure? */ - (void) assign_hold(c, &c->spd - , b->transport_proto - , &b->our_client, &b->peer_client); - } - c->gw_info->key->last_tried_time = now(); - ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); - b->whackfd = NULL_FD; /* protect from close */ - } - } - break; - - default: - bad_case(b->step); - } - - /* the second chunk: initiate the next DNS query (if any) */ - DBG(DBG_CONTROL, - { - char ours[ADDRTOT_BUF]; - char his[ADDRTOT_BUF]; - - addrtot(&b->our_client, 0, ours, sizeof(ours)); - addrtot(&b->peer_client, 0, his, sizeof(his)); - DBG_log("initiate on demand from %s to %s new state: %s with ugh: %s" - , ours, his, oppo_step_name[b->step], ugh ? ugh : "ok"); - }); - - if (ugh) - { - b->policy_prio = c->prio; - b->failure_shunt = shunt_policy_spi(c, FALSE); - cannot_oppo(c, b, ugh); - } - else if (next_step == fos_done) - { - /* nothing to do */ - } - else - { - /* set up the next query */ - struct find_oppo_continuation *cr = malloc_thing(struct find_oppo_continuation); - identification_t *id; - - b->policy_prio = c->prio; - b->failure_shunt = shunt_policy_spi(c, FALSE); - cr->b = *b; /* copy; start hand off of whackfd */ - cr->b.failure_ok = FALSE; - cr->b.step = next_step; - - for (sr = &c->spd - ; sr!=NULL && !sameaddr(&sr->this.host_addr, &b->our_client) - ; sr = sr->next) - ; - - if (sr == NULL) - sr = &c->spd; - - /* If a %hold shunt has replaced the eroute for this template, - * record this fact. - */ - if (b->held - && sr->routing == RT_ROUTED_PROSPECTIVE && eclipsable(sr)) - { - sr->routing = RT_ROUTED_ECLIPSED; - eclipse_count++; - } - - /* Switch to issue next query. - * A case may turn out to be unnecessary. If so, it falls - * through to the next case. - * Figuring out what %myid can stand for must be done before - * our client credentials are looked up: we must know what - * the client credentials may use to identify us. - * On the other hand, our own credentials should be looked - * up after our clients in case our credentials are not - * needed at all. - * XXX this is a wasted effort if we don't have credentials - * BUT they are not needed. - */ - switch (next_step) - { - case fos_myid_ip_txt: - if (c->spd.this.id->get_type(c->spd.this.id) == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = TRUE; - cr->b.want = b->want = "TXT record for IP address as %myid"; - ugh = start_adns_query(myids[MYID_IP], myids[MYID_IP], - T_TXT, continue_oppo, &cr->ac); - break; - } - cr->b.step = fos_myid_hostname_txt; - /* fall through */ - - case fos_myid_hostname_txt: - if (c->spd.this.id->get_type(c->spd.this.id) == ID_MYID - && myid_state != MYID_SPECIFIED) - { -#ifdef USE_KEYRR - cr->b.failure_ok = TRUE; -#else - cr->b.failure_ok = FALSE; -#endif - cr->b.want = b->want = "TXT record for hostname as %myid"; - ugh = start_adns_query(myids[MYID_HOSTNAME], - myids[MYID_HOSTNAME], - T_TXT, continue_oppo, &cr->ac); - break; - } - -#ifdef USE_KEYRR - cr->b.step = fos_myid_ip_key; - /* fall through */ - - case fos_myid_ip_key: - if (c->spd.this.id.kind == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = TRUE; - cr->b.want = b->want = "KEY record for IP address as %myid (no good TXT)"; - ugh = start_adns_query(myids[MYID_IP], NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; - } - cr->b.step = fos_myid_hostname_key; - /* fall through */ - - case fos_myid_hostname_key: - if (c->spd.this.id.kind == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = FALSE; /* last attempt! */ - cr->b.want = b->want = "KEY record for hostname as %myid (no good TXT)"; - ugh = start_adns_query(myids[MYID_HOSTNAME], NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; - } -#endif - cr->b.step = fos_our_client; - /* fall through */ - - case fos_our_client: /* TXT for our client */ - if (!sameaddr(&c->spd.this.host_addr, &b->our_client)) - { - /* Check that at least one TXT(reverse(b->our_client)) is workable. - * Note: {unshare|free}_id_content not needed for id: ephemeral. - */ - cr->b.want = b->want = "our client's TXT record"; - id = identification_create_from_sockaddr((sockaddr_t*)&b->our_client); - ugh = start_adns_query(id, c->spd.this.id, /* we are the security gateway */ - T_TXT, continue_oppo, &cr->ac); - id->destroy(id); - break; - } - cr->b.step = fos_our_txt; - /* fall through */ - - case fos_our_txt: /* TXT for us */ - cr->b.failure_ok = b->failure_ok = TRUE; - cr->b.want = b->want = "our TXT record"; - ugh = start_adns_query(sr->this.id, sr->this.id, /* we are the security gateway */ - T_TXT, continue_oppo, &cr->ac); - break; - -#ifdef USE_KEYRR - case fos_our_key: /* KEY for us */ - cr->b.want = b->want = "our KEY record"; - cr->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(sr->this.id, NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; -#endif /* USE_KEYRR */ - - case fos_his_client: /* TXT for his client */ - /* note: {unshare|free}_id_content not needed for id: ephemeral */ - cr->b.want = b->want = "target's TXT record"; - cr->b.failure_ok = b->failure_ok = FALSE; - id = identification_create_from_sockaddr((sockaddr_t*)&b->peer_client); - ugh = start_adns_query(id, NULL, /* security gateway unconstrained */ - T_TXT, continue_oppo, &cr->ac); - id->destroy(id); - break; - - default: - bad_case(next_step); - } - - if (ugh == NULL) - b->whackfd = NULL_FD; /* complete hand-off */ - else - cannot_oppo(c, b, ugh); - } - } -#endif /* ADNS */ - close_any(b->whackfd); -} - -void terminate_connection(const char *nm) -{ - /* Loop because more than one may match (master and instances) - * But at least one is required (enforced by con_by_name). - */ - connection_t *c = con_by_name(nm, TRUE); - - if (c == NULL || !c->ikev1) - return; - - do - { - connection_t *n = c->ac_next; /* grab this before c might disappear */ - - if (streq(c->name, nm) - && c->kind >= CK_PERMANENT - && !NEVER_NEGOTIATE(c->policy)) - { - set_cur_connection(c); - plog("terminating SAs using this connection"); - c->policy &= ~POLICY_UP; - flush_pending_by_connection(c); - delete_states_by_connection(c, FALSE); - if (c->kind == CK_INSTANCE) - delete_connection(c, FALSE); - reset_cur_connection(); - } - c = n; - } while (c); -} - -/* an ISAKMP SA has been established. - * Note the serial number, and release any connections with - * the same peer ID but different peer IP address. - */ -bool uniqueIDs = FALSE; /* --uniqueids? */ - -void ISAKMP_SA_established(connection_t *c, so_serial_t serial) -{ - c->newest_isakmp_sa = serial; - - /* the connection is now oriented so that we are able to determine - * whether we are a mode config server with a virtual IP to send. - */ - if (!c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip) && - !c->spd.that.has_natip) - { - c->spd.that.modecfg = TRUE; - } - - if (uniqueIDs) - { - /* for all connections: if the same Phase 1 IDs are used - * for a different IP address, unorient that connection. - */ - connection_t *d; - - for (d = connections; d != NULL; ) - { - connection_t *next = d->ac_next; /* might move underneath us */ - - if (d->kind >= CK_PERMANENT && - c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - c->spd.that.id->equals(c->spd.that.id, d->spd.that.id) && - !sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr)) - { - release_connection(d, FALSE); - } - d = next; - } - } -} - -/* Find the connection to connection c's peer's client with the - * largest value of .routing. All other things being equal, - * preference is given to c. If none is routed, return NULL. - * - * If erop is non-null, set *erop to a connection sharing both - * our client subnet and peer's client subnet with the largest value - * of .routing. If none is erouted, set *erop to NULL. - * - * The return value is used to find other connections sharing a route. - * *erop is used to find other connections sharing an eroute. - */ -connection_t *route_owner(connection_t *c, struct spd_route **srp, - connection_t **erop, struct spd_route **esrp) -{ - connection_t *d - , *best_ro = c - , *best_ero = c; - struct spd_route *srd, *src; - struct spd_route *best_sr, *best_esr; - enum routing_t best_routing, best_erouting; - - passert(oriented(*c)); - best_sr = NULL; - best_esr = NULL; - best_routing = c->spd.routing; - best_erouting = best_routing; - - for (d = connections; d != NULL; d = d->ac_next) - { - for (srd = &d->spd; srd; srd = srd->next) - { - if (srd->routing == RT_UNROUTED) - continue; - - for (src = &c->spd; src; src=src->next) - { - if (!samesubnet(&src->that.client, &srd->that.client)) - { - continue; - } - if (src->that.protocol != srd->that.protocol) - { - continue; - } - if (src->that.port != srd->that.port) - { - continue; - } - if (src->mark_out.value != srd->mark_out.value) - { - continue; - } - passert(oriented(*d)); - if (srd->routing > best_routing) - { - best_ro = d; - best_sr = srd; - best_routing = srd->routing; - } - - if (!samesubnet(&src->this.client, &srd->this.client)) - { - continue; - } - if (src->this.protocol != srd->this.protocol) - { - continue; - } - if (src->this.port != srd->this.port) - { - continue; - } - if (src->mark_in.value != srd->mark_in.value) - { - continue; - } - if (srd->routing > best_erouting) - { - best_ero = d; - best_esr = srd; - best_erouting = srd->routing; - } - } - } - } - - DBG(DBG_CONTROL, - { - char cib[CONN_INST_BUF]; - err_t m = builddiag("route owner of \"%s\"%s %s:" - , c->name - , (fmt_conn_instance(c, cib), cib) - , enum_name(&routing_story, c->spd.routing)); - - if (!routed(best_ro->spd.routing)) - m = builddiag("%s NULL", m); - else if (best_ro == c) - m = builddiag("%s self", m); - else - m = builddiag("%s \"%s\"%s %s", m - , best_ro->name - , (fmt_conn_instance(best_ro, cib), cib) - , enum_name(&routing_story, best_ro->spd.routing)); - - if (erop) - { - m = builddiag("%s; eroute owner:", m); - if (!erouted(best_ero->spd.routing)) - m = builddiag("%s NULL", m); - else if (best_ero == c) - m = builddiag("%s self", m); - else - m = builddiag("%s \"%s\"%s %s", m - , best_ero->name - , (fmt_conn_instance(best_ero, cib), cib) - , enum_name(&routing_story, best_ero->spd.routing)); - } - - DBG_log("%s", m); - }); - - if (erop) - { - *erop = erouted(best_erouting)? best_ero : NULL; - } - if (srp) - { - *srp = best_sr; - if (esrp) - { - *esrp = best_esr; - } - } - - return routed(best_routing)? best_ro : NULL; -} - -/* Find a connection that owns the shunt eroute between subnets. - * There ought to be only one. - * This might get to be a bottleneck -- try hashing if it does. - */ -connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his) -{ - connection_t *c; - struct spd_route *sr; - - for (c = connections; c != NULL; c = c->ac_next) - { - for (sr = &c->spd; sr; sr = sr->next) - { - if (shunt_erouted(sr->routing) - && samesubnet(ours, &sr->this.client) - && samesubnet(his, &sr->that.client)) - return c; - } - } - return NULL; -} - -/* Find some connection with this pair of hosts. - * We don't know enough to chose amongst those available. - * ??? no longer usefully different from find_host_pair_connections - */ -connection_t *find_host_connection(const ip_address *me, u_int16_t my_port, - const ip_address *him, u_int16_t his_port, - lset_t policy) -{ - connection_t *c = find_host_pair_connections(me, my_port, him, his_port); - - if (policy != LEMPTY) - { - lset_t auth_requested = policy & POLICY_ID_AUTH_MASK; - - /* if we have requirements for the policy, - * choose the first matching connection. - */ - while (c) - { - if (c->policy & auth_requested) - { - break; - } - c = c->hp_next; - } - } - return c; -} - -/* given an up-until-now satisfactory connection, find the best connection - * now that we just got the Phase 1 Id Payload from the peer. - * - * Comments in the code describe the (tricky!) matching criteria. - * Although this routine could handle the initiator case, - * it isn't currently called in this case. - * If it were, it could "upgrade" an Opportunistic Connection - * to a Road Warrior Connection if a suitable Peer ID were found. - * - * In RFC 2409 "The Internet Key Exchange (IKE)", - * in 5.1 "IKE Phase 1 Authenticated With Signatures", describing Main - * Mode: - * - * Initiator Responder - * ----------- ----------- - * HDR, SA --> - * <-- HDR, SA - * HDR, KE, Ni --> - * <-- HDR, KE, Nr - * HDR*, IDii, [ CERT, ] SIG_I --> - * <-- HDR*, IDir, [ CERT, ] SIG_R - * - * In 5.4 "Phase 1 Authenticated With a Pre-Shared Key": - * - * HDR, SA --> - * <-- HDR, SA - * HDR, KE, Ni --> - * <-- HDR, KE, Nr - * HDR*, IDii, HASH_I --> - * <-- HDR*, IDir, HASH_R - * - * refine_host_connection could be called in two case: - * - * - the Responder receives the IDii payload: - * + [PSK] after using PSK to decode this message - * + before sending its IDir payload - * + before using its ID in HASH_R computation - * + [DSig] before using its private key to sign SIG_R - * + before using the Initiator's ID in HASH_I calculation - * + [DSig] before using the Initiator's public key to check SIG_I - * - * - the Initiator receives the IDir payload: - * + [PSK] after using PSK to encode previous message and decode this message - * + after sending its IDii payload - * + after using its ID in HASH_I computation - * + [DSig] after using its private key to sign SIG_I - * + before using the Responder's ID to compute HASH_R - * + [DSig] before using Responder's public key to check SIG_R - * - * refine_host_connection can choose a different connection, as long as - * nothing already used is changed. - * - * In the Initiator case, the particular connection might have been - * specified by whatever provoked Pluto to initiate. For example: - * whack --initiate connection-name - * The advantages of switching connections when we're the Initiator seem - * less important than the disadvantages, so after FreeS/WAN 1.9, we - * don't do this. - */ -#define PRIO_NO_MATCH_FOUND 2048 - -connection_t *refine_host_connection(const struct state *st, - identification_t *peer_id, - identification_t *peer_ca) -{ - connection_t *c = st->st_connection; - connection_t *d; - connection_t *best_found = NULL; - u_int16_t auth = st->st_oakley.auth; - lset_t auth_policy = POLICY_PSK; - const chunk_t *psk = NULL; - bool wcpip; /* wildcard Peer IP? */ - int best_prio = PRIO_NO_MATCH_FOUND; - int our_pathlen, peer_pathlen; - - if (c->spd.that.id->equals(c->spd.that.id, peer_id) && - trusted_ca(peer_ca, c->spd.that.ca, &peer_pathlen) && - peer_pathlen == 0 && - match_requested_ca(c->requested_ca, c->spd.this.ca, &our_pathlen) && - our_pathlen == 0) - { - DBG(DBG_CONTROL, - DBG_log("current connection is a full match" - " -- no need to look further"); - ) - return c; - } - - switch (auth) - { - case OAKLEY_PRESHARED_KEY: - auth_policy = POLICY_PSK; - psk = get_preshared_secret(c); - /* It should be virtually impossible to fail to find PSK: - * we just used it to decode the current message! - */ - if (psk == NULL) - { - return NULL; /* cannot determine PSK! */ - } - break; - case XAUTHInitPreShared: - case XAUTHRespPreShared: - auth_policy = POLICY_XAUTH_PSK; - psk = get_preshared_secret(c); - if (psk == NULL) - { - return NULL; /* cannot determine PSK! */ - } - break; - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - auth_policy = POLICY_PUBKEY; - break; - case XAUTHInitRSA: - case XAUTHRespRSA: - auth_policy = POLICY_XAUTH_RSASIG; - break; - default: - bad_case(auth); - } - - /* The current connection won't do: search for one that will. - * First search for one with the same pair of hosts. - * If that fails, search for a suitable Road Warrior or Opportunistic - * connection (i.e. wildcard peer IP). - * We need to match: - * - peer_id (slightly complicated by instantiation) - * - if PSK auth, the key must not change (we used it to decode message) - * - policy-as-used must be acceptable to new connection - */ - d = c->host_pair->connections; - for (wcpip = FALSE; ; wcpip = TRUE) - { - for (; d != NULL; d = d->hp_next) - { - const char *match_name[] = {"no", "ok"}; - - id_match_t match_level = peer_id->matches(peer_id, d->spd.that.id); - - bool matching_id = match_level > ID_MATCH_NONE; - - bool matching_auth = (d->policy & auth_policy) != LEMPTY; - - bool matching_trust = trusted_ca(peer_ca - , d->spd.that.ca, &peer_pathlen); - bool matching_request = match_requested_ca(c->requested_ca - , d->spd.this.ca, &our_pathlen); - bool match = matching_id && matching_auth && matching_trust; - - int prio = (ID_MATCH_PERFECT) * !matching_request + - ID_MATCH_PERFECT - match_level; - - prio = (X509_MAX_PATH_LEN + 1) * prio + peer_pathlen; - prio = (X509_MAX_PATH_LEN + 1) * prio + our_pathlen; - - DBG(DBG_CONTROLMORE, - DBG_log("%s: %s match (id: %s, auth: %s, trust: %s, request: %s, prio: %4d)" - , d->name - , match ? "full":" no" - , match_name[matching_id] - , match_name[matching_auth] - , match_name[matching_trust] - , match_name[matching_request] - , match ? prio:PRIO_NO_MATCH_FOUND) - ) - - /* do we have a match? */ - if (!match) - { - continue; - } - - /* ignore group connections */ - if (d->policy & POLICY_GROUP) - { - continue; - } - - if (c->spd.that.host_port != d->spd.that.host_port - && d->kind == CK_INSTANCE) - { - continue; - } - - switch (auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - /* secret must match the one we already used */ - { - const chunk_t *dpsk = get_preshared_secret(d); - - if (dpsk == NULL) - { - continue; /* no secret */ - } - if (psk != dpsk) - { - if (psk->len != dpsk->len - || memcmp(psk->ptr, dpsk->ptr, psk->len) != 0) - { - continue; /* different secret */ - } - } - } - break; - - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - /* - * We must at least be able to find our private key - .*/ - if (d->spd.this.sc == NULL /* no smartcard */ - && get_private_key(d) == NULL) /* no private key */ - { - continue; - } - break; - - default: - bad_case(auth); - } - - /* d has passed all the tests. - * We'll go with it if the Peer ID was an exact match. - */ - if (prio == 0) - { - return d; - } - - /* We'll remember it as best_found in case an exact - * match doesn't come along. - */ - if (prio < best_prio) - { - best_found = d; - best_prio = prio; - } - } - if (wcpip) - return best_found; /* been around twice already */ - - /* Starting second time around. - * We're willing to settle for a connection that needs Peer IP - * instantiated: Road Warrior or Opportunistic. - * Look on list of connections for host pair with wildcard Peer IP - */ - d = find_host_pair_connections(&c->spd.this.host_addr, c->spd.this.host_port - , (ip_address *)NULL, c->spd.that.host_port); - } -} - -/** - * With virtual addressing, we must not allow someone to use an already - * used (by another id) addr/net. - */ -static bool is_virtual_net_used(const ip_subnet *peer_net, - identification_t *peer_id) -{ - connection_t *d; - - for (d = connections; d != NULL; d = d->ac_next) - { - switch (d->kind) - { - case CK_PERMANENT: - case CK_INSTANCE: - if ((subnetinsubnet(peer_net,&d->spd.that.client) || - subnetinsubnet(&d->spd.that.client,peer_net)) - && !d->spd.that.id->equals(d->spd.that.id, peer_id)) - { - char client[SUBNETTOT_BUF]; - - subnettot(peer_net, 0, client, sizeof(client)); - plog("Virtual IP %s is already used by '%Y'", - client, d->spd.that.id); - plog("Your ID is '%Y'", peer_id); - - return TRUE; /* already used by another one */ - } - break; - case CK_GOING_AWAY: - default: - break; - } - } - return FALSE; /* you can safely use it */ -} - -/* find_client_connection: given a connection suitable for ISAKMP - * (i.e. the hosts match), find a one suitable for IPSEC - * (i.e. with matching clients). - * - * If we don't find an exact match (not even our current connection), - * we try for one that still needs instantiation. Try Road Warrior - * abstract connections and the Opportunistic abstract connections. - * This requires inverse instantiation: abstraction. - * - * After failing to find an exact match, we abstract the peer - * to be NO_IP (the wildcard value). This enables matches with - * Road Warrior and Opportunistic abstract connections. - * - * After failing that search, we also abstract the Phase 1 peer ID - * if possible. If the peer's ID was the peer's IP address, we make - * it NO_ID; instantiation will make it the peer's IP address again. - * - * If searching for a Road Warrior abstract connection fails, - * and conditions are suitable, we search for the best Opportunistic - * abstract connection. - * - * Note: in the end, both Phase 1 IDs must be preserved, after any - * instantiation. They are the IDs that have been authenticated. - */ - -#define PATH_WEIGHT 1 -#define WILD_WEIGHT (X509_MAX_PATH_LEN+1) -#define PRIO_WEIGHT (ID_MATCH_PERFECT+1) * WILD_WEIGHT - -/* fc_try: a helper function for find_client_connection */ -static connection_t *fc_try(const connection_t *c, struct host_pair *hp, - identification_t *peer_id, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port, - identification_t *peer_ca, - ietf_attributes_t *peer_attributes) -{ - connection_t *d; - connection_t *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - id_match_t match_level; - int pathlen; - - - const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr); - - for (d = hp->connections; d != NULL; d = d->hp_next) - { - struct spd_route *sr; - - if (d->policy & POLICY_GROUP) - { - continue; - } - - match_level = c->spd.that.id->matches(c->spd.that.id, d->spd.that.id); - - if (!(c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - (match_level > ID_MATCH_NONE) && - trusted_ca(peer_ca, d->spd.that.ca, &pathlen) && - match_group_membership(peer_attributes, d->name, d->spd.that.groups))) - { - continue; - } - - /* compare protocol and ports */ - if (d->spd.this.protocol != our_protocol - || d->spd.this.port != our_port - || d->spd.that.protocol != peer_protocol - || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) - { - continue; - } - - /* non-Opportunistic case: - * our_client must match. - * - * So must peer_client, but the testing is complicated - * by the fact that the peer might be a wildcard - * and if so, the default value of that.client - * won't match the default peer_net. The appropriate test: - * - * If d has a peer client, it must match peer_net. - * If d has no peer client, peer_net must just have peer itself. - */ - - for (sr = &d->spd; best != d && sr != NULL; sr = sr->next) - { - policy_prio_t prio; -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - subnettot(&sr->this.client, 0, s3, sizeof(s3)); - subnettot(&sr->that.client, 0, d3, sizeof(d3)); - DBG_log(" fc_try trying " - "%s:%s:%d/%d -> %s:%d/%d vs %s:%s:%d/%d -> %s:%d/%d" - , c->name, s1, c->spd.this.protocol, c->spd.this.port - , d1, c->spd.that.protocol, c->spd.that.port - , d->name, s3, sr->this.protocol, sr->this.port - , d3, sr->that.protocol, sr->that.port); - } -#endif /* DEBUG */ - - if (!samesubnet(&sr->this.client, our_net)) - { - continue; - } - if (sr->that.has_client) - { - if (sr->that.has_client_wildcard) - { - if (!subnetinsubnet(peer_net, &sr->that.client)) - { - continue; - } - } - else - { - if (!samesubnet(&sr->that.client, peer_net) && !is_virtual_connection(d)) - { - continue; - } - if (is_virtual_connection(d) - && (!is_virtual_net_allowed(d, peer_net, &c->spd.that.host_addr) - || is_virtual_net_used(peer_net, peer_id?peer_id:c->spd.that.id))) - { - continue; - } - } - } - else - { - host_t *vip = c->spd.that.host_srcip; - - if (!peer_net_is_host && !(sr->that.modecfg && c->spd.that.modecfg && - subnetisaddr(peer_net, (ip_address*)vip->get_sockaddr(vip)))) - { - continue; - } - } - - /* We've run the gauntlet -- success: - * We've got an exact match of subnets. - * The connection is feasible, but we continue looking for the best. - * The highest priority wins, implementing eroute-like rule. - * - a routed connection is preferrred - * - given that, the smallest number of ID wildcards are preferred - * - given that, the shortest CA pathlength is preferred - */ - prio = PRIO_WEIGHT * routed(sr->routing) - + WILD_WEIGHT * match_level - + PATH_WEIGHT * (X509_MAX_PATH_LEN - pathlen) - + 1; - if (prio > best_prio) - { - best = d; - best_prio = prio; - } - } - } - - if (best && NEVER_NEGOTIATE(best->policy)) - { - best = NULL; - } - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try concluding with %s [%ld]" - , (best ? best->name : "none"), best_prio) - ) - return best; -} - -static connection_t *fc_try_oppo(const connection_t *c, - struct host_pair *hp, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port, - identification_t *peer_ca, - ietf_attributes_t *peer_attributes) -{ - connection_t *d; - connection_t *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - id_match_t match_level; - int pathlen; - - for (d = hp->connections; d != NULL; d = d->hp_next) - { - struct spd_route *sr; - policy_prio_t prio; - - if (d->policy & POLICY_GROUP) - { - continue; - } - match_level = c->spd.that.id->matches(c->spd.that.id, c->spd.that.id); - - if (!(c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - (match_level > ID_MATCH_NONE) && - trusted_ca(peer_ca, d->spd.that.ca, &pathlen) && - match_group_membership(peer_attributes, d->name, d->spd.that.groups))) - { - continue; - } - - /* compare protocol and ports */ - if (d->spd.this.protocol != our_protocol - || d->spd.this.port != our_port - || d->spd.that.protocol != peer_protocol - || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) - { - continue; - } - - /* Opportunistic case: - * our_net must be inside d->spd.this.client - * and peer_net must be inside d->spd.that.client - * Note: this host_pair chain also has shunt - * eroute conns (clear, drop), but they won't - * be marked as opportunistic. - */ - for (sr = &d->spd; sr != NULL; sr = sr->next) - { -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - subnettot(&sr->this.client, 0, s3, sizeof(s3)); - subnettot(&sr->that.client, 0, d3, sizeof(d3)); - DBG_log(" fc_try_oppo trying %s:%s -> %s vs %s:%s -> %s" - , c->name, s1, d1, d->name, s3, d3); - } -#endif /* DEBUG */ - - if (!subnetinsubnet(our_net, &sr->this.client) - || !subnetinsubnet(peer_net, &sr->that.client)) - { - continue; - } - - /* The connection is feasible, but we continue looking for the best. - * The highest priority wins, implementing eroute-like rule. - * - our smallest client subnet is preferred (longest mask) - * - given that, his smallest client subnet is preferred - * - given that, a routed connection is preferrred - * - given that, the smallest number of ID wildcards are preferred - * - given that, the shortest CA pathlength is preferred - */ - prio = PRIO_WEIGHT * (d->prio + routed(sr->routing)) - + WILD_WEIGHT * match_level - + PATH_WEIGHT * (X509_MAX_PATH_LEN - pathlen); - if (prio > best_prio) - { - best = d; - best_prio = prio; - } - } - } - - /* if the best wasn't opportunistic, we fail: it must be a shunt */ - if (best && (NEVER_NEGOTIATE(best->policy) || - (best->policy & POLICY_OPPO) == LEMPTY)) - { - best = NULL; - } - - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try_oppo concluding with %s [%ld]" - , (best ? best->name : "none"), best_prio) - ) - return best; - -} - -/* - * get the peer's CA and group attributes - */ -void get_peer_ca_and_groups(connection_t *c, - identification_t **peer_ca, - ietf_attributes_t **peer_attributes) -{ - struct state *p1st; - - *peer_ca = NULL; - *peer_attributes = NULL; - - p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - if (p1st && p1st->st_peer_pubkey && p1st->st_peer_pubkey->issuer) - { - certificate_t *cert; - - cert = ac_get_cert(p1st->st_peer_pubkey->issuer, - p1st->st_peer_pubkey->serial); - if (cert && ac_verify_cert(cert, strict_crl_policy)) - { - ac_t *ac = (ac_t*)cert; - - *peer_attributes = ac->get_groups(ac); - } - else - { - DBG(DBG_CONTROL, - DBG_log("no valid attribute cert found") - ) - } - *peer_ca = p1st->st_peer_pubkey->issuer; - } -} - -connection_t *find_client_connection(connection_t *c, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port) -{ - connection_t *d; - struct spd_route *sr; - ietf_attributes_t *peer_attributes = NULL; - identification_t *peer_ca; - - get_peer_ca_and_groups(c, &peer_ca, &peer_attributes); - -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - - DBG_log("find_client_connection starting with %s" - , (c ? c->name : "(none)")); - DBG_log(" looking for %s:%d/%d -> %s:%d/%d" - , s1, our_protocol, our_port - , d1, peer_protocol, peer_port); - } -#endif /* DEBUG */ - - /* give priority to current connection - * but even greater priority to a routed concrete connection - */ - { - connection_t *unrouted = NULL; - int srnum = -1; - - for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next) - { - srnum++; - -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF]; - - subnettot(&sr->this.client, 0, s2, sizeof(s2)); - subnettot(&sr->that.client, 0, d2, sizeof(d2)); - DBG_log(" concrete checking against sr#%d %s -> %s" - , srnum, s2, d2); - } -#endif /* DEBUG */ - - if (samesubnet(&sr->this.client, our_net) - && samesubnet(&sr->that.client, peer_net) - && sr->this.protocol == our_protocol - && sr->this.port == our_port - && sr->that.protocol == peer_protocol - && sr->that.port == peer_port - && match_group_membership(peer_attributes, c->name, sr->that.groups)) - { - passert(oriented(*c)); - if (routed(sr->routing)) - { - DESTROY_IF(peer_attributes); - return c; - } - unrouted = c; - } - } - - /* exact match? */ - d = fc_try(c, c->host_pair, NULL, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try %s gives %s" - , c->name - , (d ? d->name : "none")) - ) - - if (d == NULL) - { - d = unrouted; - } - } - - if (d == NULL) - { - /* look for an abstract connection to match */ - struct spd_route *sr; - struct host_pair *hp = NULL; - - for (sr = &c->spd; hp==NULL && sr != NULL; sr = sr->next) - { - hp = find_host_pair(&sr->this.host_addr - , sr->this.host_port - , NULL - , sr->that.host_port); -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF]; - - subnettot(&sr->this.client, 0, s2, sizeof(s2)); - subnettot(&sr->that.client, 0, d2, sizeof(d2)); - - DBG_log(" checking hostpair %s -> %s is %s" - , s2, d2 - , (hp ? "found" : "not found")); - } -#endif /* DEBUG */ - } - - if (hp) - { - /* RW match with actual peer_id or abstract peer_id? */ - d = fc_try(c, hp, NULL, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - - if (d == NULL - && subnetishost(our_net) - && subnetishost(peer_net)) - { - /* Opportunistic match? - * Always use abstract peer_id. - * Note that later instantiation will result in the same peer_id. - */ - d = fc_try_oppo(c, hp, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - } - } - } - - DBG(DBG_CONTROLMORE, - DBG_log(" concluding with d = %s" - , (d ? d->name : "none")) - ) - DESTROY_IF(peer_attributes); - return d; -} - -int connection_compare(const connection_t *ca, const connection_t *cb) -{ - int ret; - - /* DBG_log("comparing %s to %s", ca->name, cb->name); */ - - ret = strcasecmp(ca->name, cb->name); - if (ret) - { - return ret; - } - - ret = ca->kind - cb->kind; /* note: enum connection_kind behaves like int */ - if (ret) - { - return ret; - } - - /* same name, and same type */ - switch (ca->kind) - { - case CK_INSTANCE: - return ca->instance_serial < cb->instance_serial ? -1 - : ca->instance_serial > cb->instance_serial ? 1 - : 0; - - default: - return ca->prio < cb->prio ? -1 - : ca->prio > cb->prio ? 1 - : 0; - } -} - -static int connection_compare_qsort(const void *a, const void *b) -{ - return connection_compare(*(const connection_t *const *)a - , *(const connection_t *const *)b); -} - -void show_connections_status(bool all, const char *name) -{ - connection_t *c; - int count, i; - connection_t **array; - - /* make an array of connections, and sort it */ - count = 0; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->ikev1 && (name == NULL || streq(c->name, name))) - count++; - } - array = malloc(sizeof(connection_t *)*count); - - count=0; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->ikev1 && (name == NULL || streq(c->name, name))) - array[count++]=c; - } - - /* sort it! */ - qsort(array, count, sizeof(connection_t *), connection_compare_qsort); - - for (i = 0; i < count; i++) - { - const char *ifn; - char instance[1 + 10 + 1]; - char prio[POLICY_PRIO_BUF]; - - c = array[i]; - - ifn = oriented(*c)? c->interface->rname : ""; - - instance[0] = '\0'; - if (c->kind == CK_INSTANCE && c->instance_serial != 0) - snprintf(instance, sizeof(instance), "[%lu]", c->instance_serial); - - /* show topology */ - { - char topo[BUF_LEN]; - struct spd_route *sr = &c->spd; - int num=0; - - while (sr) - { - (void) format_connection(topo, sizeof(topo), c, sr); - whack_log(RC_COMMENT, "\"%s\"%s: %s; %s; eroute owner: #%lu" - , c->name, instance, topo - , enum_name(&routing_story, sr->routing) - , sr->eroute_owner); - sr = sr->next; - num++; - } - } - - if (all) - { - /* show CAs if defined */ - if (c->spd.this.ca && c->spd.that.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: \"%Y\"...\"%Y\"", - c->name, instance, c->spd.this.ca, c->spd.that.ca); - } - else if (c->spd.this.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: \"%Y\"...%%any", - c->name, instance, c->spd.this.ca); - - } - else if (c->spd.that.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: %%any...\"%Y\"", - c->name, instance, c->spd.that.ca); - } - - /* show group attributes if defined */ - if (c->spd.that.groups) - { - whack_log(RC_COMMENT, "\"%s\"%s: groups: %s" - , c->name - , instance - , c->spd.that.groups->get_string(c->spd.that.groups)); - } - - whack_log(RC_COMMENT - , "\"%s\"%s: ike_life: %lus; ipsec_life: %lus;" - " rekey_margin: %lus; rekey_fuzz: %lu%%; keyingtries: %lu" - , c->name - , instance - , (unsigned long) c->sa_ike_life_seconds - , (unsigned long) c->sa_ipsec_life_seconds - , (unsigned long) c->sa_rekey_margin - , (unsigned long) c->sa_rekey_fuzz - , (unsigned long) c->sa_keying_tries); - - /* show DPD parameters if defined */ - - if (c->dpd_action != DPD_ACTION_NONE) - whack_log(RC_COMMENT - , "\"%s\"%s: dpd_action: %N;" - " dpd_delay: %lus; dpd_timeout: %lus;" - , c->name - , instance - , dpd_action_names, c->dpd_action - , (unsigned long) c->dpd_delay - , (unsigned long) c->dpd_timeout); - - if (c->policy_next) - { - whack_log(RC_COMMENT - , "\"%s\"%s: policy_next: %s" - , c->name, instance, c->policy_next->name); - } - - /* Note: we display key_from_DNS_on_demand as if policy [lr]KOD */ - fmt_policy_prio(c->prio, prio); - whack_log(RC_COMMENT - , "\"%s\"%s: policy: %s%s%s; prio: %s; interface: %s; " - , c->name - , instance - , prettypolicy(c->policy) - , c->spd.this.key_from_DNS_on_demand? "+lKOD" : "" - , c->spd.that.key_from_DNS_on_demand? "+rKOD" : "" - , prio - , ifn); - } - - whack_log(RC_COMMENT - , "\"%s\"%s: newest ISAKMP SA: #%ld; newest IPsec SA: #%ld; " - , c->name - , instance - , c->newest_isakmp_sa - , c->newest_ipsec_sa); - - if (all) - { - ike_alg_show_connection(c, instance); - kernel_alg_show_connection(c, instance); - } - } - if (count > 0) - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - - free(array); -} - -/* struct pending, the structure representing Quick Mode - * negotiations delayed until a Keying Channel has been negotiated. - * Essentially, a pending call to quick_outI1. - */ - -struct pending { - int whack_sock; - struct state *isakmp_sa; - connection_t *connection; - lset_t policy; - unsigned long try; - so_serial_t replacing; - - struct pending *next; -}; - -/* queue a Quick Mode negotiation pending completion of a suitable Main Mode */ -void add_pending(int whack_sock, struct state *isakmp_sa, connection_t *c, - lset_t policy, unsigned long try, so_serial_t replacing) -{ - bool already_queued = FALSE; - struct pending *p = c->host_pair->pending; - - while (p) - { - if (streq(c->name, p->connection->name)) - { - already_queued = TRUE; - break; - } - p = p->next; - } - DBG(DBG_CONTROL, - DBG_log("Queuing pending Quick Mode with %s \"%s\"%s" - , ip_str(&c->spd.that.host_addr) - , c->name - , already_queued? " already done" : "") - ) - if (already_queued) - return; - - p = malloc_thing(struct pending); - p->whack_sock = whack_sock; - p->isakmp_sa = isakmp_sa; - p->connection = c; - p->policy = policy; - p->try = try; - p->replacing = replacing; - p->next = c->host_pair->pending; - c->host_pair->pending = p; -} - -/* Release all the whacks awaiting the completion of this state. - * This is accomplished by closing all the whack socket file descriptors. - * We go to a lot of trouble to tell each whack, but to not tell it twice. - */ -void release_pending_whacks(struct state *st, err_t story) -{ - struct pending *p; - struct stat stst; - - if (st->st_whack_sock == NULL_FD || fstat(st->st_whack_sock, &stst) != 0) - zero(&stst); /* resulting st_dev/st_ino ought to be distinct */ - - release_whack(st); - - for (p = st->st_connection->host_pair->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == st && p->whack_sock != NULL_FD) - { - struct stat pst; - - if (fstat(p->whack_sock, &pst) == 0 - && (stst.st_dev != pst.st_dev || stst.st_ino != pst.st_ino)) - { - passert(whack_log_fd == NULL_FD); - whack_log_fd = p->whack_sock; - whack_log(RC_COMMENT - , "%s for ISAKMP SA, but releasing whack for pending IPSEC SA" - , story); - whack_log_fd = NULL_FD; - } - close(p->whack_sock); - p->whack_sock = NULL_FD; - } - } -} - -static void delete_pending(struct pending **pp) -{ - struct pending *p = *pp; - - *pp = p->next; - if (p->connection) - { - connection_discard(p->connection); - } - close_any(p->whack_sock); - free(p); -} - -void unpend(struct state *st) -{ - struct pending **pp - , *p; - - for (pp = &st->st_connection->host_pair->pending; (p = *pp) != NULL; ) - { - if (p->isakmp_sa == st) - { - DBG(DBG_CONTROL, DBG_log("unqueuing pending Quick Mode with %s \"%s\"" - , ip_str(&p->connection->spd.that.host_addr) - , p->connection->name)); - (void) quick_outI1(p->whack_sock, st, p->connection, p->policy - , p->try, p->replacing); - p->whack_sock = NULL_FD; /* ownership transferred */ - p->connection = NULL; /* ownership transferred */ - delete_pending(pp); - } - else - { - pp = &p->next; - } - } -} - -/* a Main Mode negotiation has been replaced; update any pending */ -void update_pending(struct state *os, struct state *ns) -{ - struct pending *p; - - for (p = os->st_connection->host_pair->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == os) - p->isakmp_sa = ns; - if (p->connection->spd.this.host_port != ns->st_connection->spd.this.host_port) - { - p->connection->spd.this.host_port = ns->st_connection->spd.this.host_port; - p->connection->spd.that.host_port = ns->st_connection->spd.that.host_port; - } - } -} - -/* a Main Mode negotiation has failed; discard any pending */ -void flush_pending_by_state(struct state *st) -{ - struct host_pair *hp = st->st_connection->host_pair; - - if (hp) - { - struct pending **pp - , *p; - - for (pp = &hp->pending; (p = *pp) != NULL; ) - { - if (p->isakmp_sa == st) - delete_pending(pp); - else - pp = &p->next; - } - } -} - -/* a connection has been deleted; discard any related pending */ -static void flush_pending_by_connection(connection_t *c) -{ - if (c->host_pair) - { - struct pending **pp - , *p; - - for (pp = &c->host_pair->pending; (p = *pp) != NULL; ) - { - if (p->connection == c) - { - p->connection = NULL; /* prevent delete_pending from releasing */ - delete_pending(pp); - } - else - { - pp = &p->next; - } - } - } -} - -void show_pending_phase2(const struct host_pair *hp, const struct state *st) -{ - const struct pending *p; - - for (p = hp->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == st) - { - /* connection-name state-number [replacing state-number] */ - char cip[CONN_INST_BUF]; - - fmt_conn_instance(p->connection, cip); - whack_log(RC_COMMENT, "#%lu: pending Phase 2 for \"%s\"%s replacing #%lu" - , p->isakmp_sa->st_serialno - , p->connection->name - , cip - , p->replacing); - } - } -} - -/* Delete a connection if it is an instance and it is no longer in use. - * We must be careful to avoid circularity: - * we don't touch it if it is CK_GOING_AWAY. - */ -void connection_discard(connection_t *c) -{ - if (c->kind == CK_INSTANCE) - { - /* see if it is being used by a pending */ - struct pending *p; - - for (p = c->host_pair->pending; p != NULL; p = p->next) - if (p->connection == c) - return; /* in use, so we're done */ - - if (!states_use_connection(c)) - delete_connection(c, FALSE); - } -} - - -/* A template connection's eroute can be eclipsed by - * either a %hold or an eroute for an instance iff - * the template is a /32 -> /32. This requires some special casing. - */ - -long eclipse_count = 0; - -connection_t *eclipsed(connection_t *c, struct spd_route **esrp) -{ - connection_t *ue; - struct spd_route *sr1 = &c->spd; - - ue = NULL; - - while (sr1 && ue) - { - for (ue = connections; ue != NULL; ue = ue->ac_next) - { - struct spd_route *srue = &ue->spd; - - while (srue && srue->routing == RT_ROUTED_ECLIPSED - && !(samesubnet(&sr1->this.client, &srue->this.client) - && samesubnet(&sr1->that.client, &srue->that.client))) - { - srue = srue->next; - } - if (srue && srue->routing == RT_ROUTED_ECLIPSED) - { - *esrp = srue; - break; - } - } - } - return ue; -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/connections.h b/src/pluto/connections.h deleted file mode 100644 index e3775fcb0..000000000 --- a/src/pluto/connections.h +++ /dev/null @@ -1,366 +0,0 @@ -/* information about connections between hosts and clients - * Copyright (C) 1998-2001 D. Hugh Redelmeier - * Copyright (C) 2009-2010 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CONNECTIONS_H -#define _CONNECTIONS_H - -#include - -#include -#include -#include -#include - -#include "certs.h" -#include "smartcard.h" -#include "whack.h" - -/* There are two kinds of connections: - * - ISAKMP connections, between hosts (for IKE communication) - * - IPsec connections, between clients (for secure IP communication) - * - * An ISAKMP connection looks like: - * host<--->host - * - * An IPsec connection looks like: - * client-subnet<-->host<->nexthop<--->nexthop<->host<-->client-subnet - * - * For the connection to be relevant to this instance of Pluto, - * exactly one of the hosts must be a public interface of our machine - * known to this instance. - * - * The client subnet might simply be the host -- this is a - * representation of "host mode". - * - * Each nexthop defaults to the neighbouring host's IP address. - * The nexthop is a property of the pair of hosts, not each - * individually. It is only needed for IPsec because of the - * way IPsec is mixed into the kernel routing logic. Furthermore, - * only this end's nexthop is actually used. Eventually, nexthop - * will be unnecessary. - * - * Other information represented: - * - each connection has a name: a chunk of uninterpreted text - * that is unique for each connection. - * - security requirements (currently just the "policy" flags from - * the whack command to initiate the connection, but eventually - * much more. Different for ISAKMP and IPsec connections. - * - rekeying parameters: - * + time an SA may live - * + time before SA death that a rekeying should be attempted - * (only by the initiator) - * + number of times to attempt rekeying - * - With the current KLIPS, we must route packets for a client - * subnet through the ipsec interface (ipsec0). Only one - * gateway can get traffic for a specific (client) subnet. - * Furthermore, if the routing isn't in place, packets will - * be sent in the clear. - * "routing" indicates whether the routing has been done for - * this connection. Note that several connections may claim - * the same routing, as long as they agree about where the - * packets are to be sent. - * - With the current KLIPS, only one outbound IPsec SA bundle can be - * used for a particular client. This is due to a limitation - * of using only routing for selection. So only one IPsec state (SA) - * may "own" the eroute. "eroute_owner" is the serial number of - * this state, SOS_NOBODY if there is none. "routing" indicates - * what kind of erouting has been done for this connection, if any. - * - * Details on routing is in constants.h - * - * Operations on Connections: - * - * - add a new connection (with all details) [whack command] - * - delete a connection (by name) [whack command] - * - initiate a connection (by name) [whack command] - * - find a connection (by IP addresses of hosts) - * [response to peer request; finding ISAKMP connection for IPsec connection] - * - * Some connections are templates, missing the address of the peer - * (represented by INADDR_ANY). These are always arranged so that the - * missing end is "that" (there can only be one missing end). These can - * be instantiated (turned into real connections) by Pluto in one of two - * different ways: Road Warrior Instantiation or Opportunistic - * Instantiation. A template connection is marked for Opportunistic - * Instantiation by specifying the peer client as 0.0.0.0/32 (or the IPV6 - * equivalent). Otherwise, it is suitable for Road Warrior Instantiation. - * - * Instantiation creates a new temporary connection, with the missing - * details filled in. The resulting template lasts only as long as there - * is a state that uses it. - */ - -/* connection policy priority: how important this policy is - * - used to implement eroute-like precedence (augmented by a small - * bonus for a routed connection). - * - a whole number - * - larger is more important - * - three subcomponents. In order of decreasing significance: - * + length of source subnet mask (8 bits) - * + length of destination subnet mask (8 bits) - * + bias (8 bit) - * - a bias of 1 is added to allow prio BOTTOM_PRIO to be less than all - * normal priorities - * - other bias values are created on the fly to give mild preference - * to certaion conditions (eg. routedness) - * - priority is inherited -- an instance of a policy has the same priority - * as the original policy, even though its subnets might be smaller. - * - display format: n,m - */ -typedef unsigned long policy_prio_t; -#define BOTTOM_PRIO ((policy_prio_t)0) /* smaller than any real prio */ -#define set_policy_prio(c) { (c)->prio = \ - ((policy_prio_t)(c)->spd.this.client.maskbits << 16) \ - | ((policy_prio_t)(c)->spd.that.client.maskbits << 8) \ - | (policy_prio_t)1; } -#define POLICY_PRIO_BUF (3+1+3+1) -extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]); - -struct virtual_t; - -struct end { - identification_t *id; - ip_address host_addr, host_nexthop; - host_t *host_srcip; - ip_subnet client; - - bool is_left; - bool key_from_DNS_on_demand; - bool has_client; - bool has_client_wildcard; - bool has_port_wildcard; - bool has_id_wildcards; - bool has_natip; - char *updown; - u_int16_t host_port; /* host order */ - u_int16_t port; /* host order */ - u_int8_t protocol; - cert_t *cert; /* end certificate */ - identification_t *ca; /* CA distinguished name */ - ietf_attributes_t *groups; /* access control groups */ - smartcard_t *sc; /* smartcard reader and key info */ - struct virtual_t *virt; - bool modecfg; /* this end: request local address from server */ - /* that end: give local addresses to clients */ - char *pool; /* name of an associated virtual IP address pool */ - bool hostaccess; /* allow access to host via iptables INPUT/OUTPUT */ - /* rules if client behind host is a subnet */ - bool allow_any; /* IP address is subject to change */ - certpolicy_t sendcert; /* whether or not to send the certificate */ -}; - -struct spd_route { - struct spd_route *next; - struct end this; - struct end that; - so_serial_t eroute_owner; - enum routing_t routing; /* level of routing in place */ - uint32_t reqid; - mark_t mark_in; - mark_t mark_out; -}; - -typedef struct connection connection_t; - -struct connection { - char *name; - bool ikev1; - - lset_t policy; - time_t sa_ike_life_seconds; - time_t sa_ipsec_life_seconds; - time_t sa_rekey_margin; - unsigned long sa_rekey_fuzz; - unsigned long sa_keying_tries; - - identification_t *xauth_identity; /* XAUTH identity */ - - /* RFC 3706 DPD */ - time_t dpd_delay; - time_t dpd_timeout; - dpd_action_t dpd_action; - - char *log_file_name; /* name of log file */ - FILE *log_file; /* possibly open FILE */ - TAILQ_ENTRY(connection) log_link; /* linked list of open conns */ - bool log_file_err; /* only bitch once */ - - struct spd_route spd; - - /* internal fields: */ - - unsigned long instance_serial; - policy_prio_t prio; - bool instance_initiation_ok; /* this is an instance of a policy that mandates initiate */ - enum connection_kind kind; - const struct iface *interface; /* filled in iff oriented */ - - so_serial_t /* state object serial number */ - newest_isakmp_sa, - newest_ipsec_sa; - - -#ifdef DEBUG - lset_t extra_debugging; -#endif - - /* note: if the client is the gateway, the following must be equal */ - sa_family_t addr_family; /* between gateways */ - sa_family_t tunnel_addr_family; /* between clients */ - - connection_t *policy_next; /* if multiple policies, - next one to apply */ - struct gw_info *gw_info; - struct alg_info_esp *alg_info_esp; - struct alg_info_ike *alg_info_ike; - struct host_pair *host_pair; - connection_t *hp_next; /* host pair list link */ - connection_t *ac_next; /* all connections list link */ - linked_list_t *requested_ca; /* collected certificate requests */ - linked_list_t *requested; /* requested attributes with handlers */ - linked_list_t *attributes; /* configuration attributes with handlers */ - bool got_certrequest; -}; - -#define oriented(c) ((c).interface != NULL) -extern bool orient(connection_t *c); - -extern bool same_peer_ids(const connection_t *c, const connection_t *d, - identification_t *his_id); - -/* Format the topology of a connection end, leaving out defaults. - * Largest left end looks like: client === host : port [ host_id ] --- hop - * Note: if that==NULL, skip nexthop - */ -#define END_BUF (SUBNETTOT_BUF + ADDRTOT_BUF + IDTOA_BUF + ADDRTOT_BUF + 10) -extern size_t format_end(char *buf, size_t buf_len, const struct end *this, - const struct end *that, bool is_left, lset_t policy); - -extern void add_connection(const whack_message_t *wm); -extern void initiate_connection(const char *name, int whackfd); -extern void initiate_opportunistic(const ip_address *our_client, - const ip_address *peer_client, - int transport_proto, bool held, int whackfd); -extern void terminate_connection(const char *nm); -extern void release_connection(connection_t *c, bool relations); -extern void delete_connection(connection_t *c, bool relations); -extern void delete_connections_by_name(const char *name, bool strict); -extern void delete_every_connection(void); -extern char *add_group_instance(connection_t *group, const ip_subnet *target); -extern void remove_group_instance(const connection_t *group, const char *name); -extern void release_dead_interfaces(void); -extern void check_orientations(void); -extern connection_t *route_owner(connection_t *c, struct spd_route **srp, - connection_t **erop, struct spd_route **esrp); -extern connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his); - -extern bool uniqueIDs; /* --uniqueids? */ -extern void ISAKMP_SA_established(connection_t *c, so_serial_t serial); - -#define id_is_ipaddr(id) ((id)->get_type(id) == ID_IPV4_ADDR || \ - (id)->get_type(id) == ID_IPV6_ADDR) -extern bool his_id_was_instantiated(const connection_t *c); - -struct state; /* forward declaration of tag (defined in state.h) */ - -extern connection_t* con_by_name(const char *nm, bool strict); -extern connection_t* find_host_connection(const ip_address *me, - u_int16_t my_port, - const ip_address *him, - u_int16_t his_port, lset_t policy); -extern connection_t* refine_host_connection(const struct state *st, - identification_t *id, - identification_t *peer_ca); -extern connection_t* find_client_connection(connection_t *c, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t out_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port); -extern connection_t* find_connection_by_reqid(uint32_t reqid); -extern connection_t* find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto); -extern void get_peer_ca_and_groups(connection_t *c, - identification_t **peer_ca, - ietf_attributes_t **peer_attributes); - -/* instantiating routines - * Note: connection_discard() is in state.h because all its work - * is looking through state objects. - */ -struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ -struct alg_info; /* forward declaration of tag (defined in alg_info.h) */ -extern connection_t *rw_instantiate(connection_t *c, - const ip_address *him, - u_int16_t his_port, - const ip_subnet *his_net, - identification_t *his_id); - -extern connection_t *oppo_instantiate(connection_t *c, - const ip_address *him, - identification_t *his_id, - struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client); - -extern connection_t - *build_outgoing_opportunistic_connection(struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client); - -#define CONN_INST_BUF BUF_LEN - -extern void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]); - -/* operations on "pending", the structure representing Quick Mode - * negotiations delayed until a Keying Channel has been negotiated. - */ - -struct pending; /* forward declaration (opaque outside connections.c) */ - -extern void add_pending(int whack_sock, struct state *isakmp_sa, - connection_t *c, lset_t policy, unsigned long try, - so_serial_t replacing); - -extern void release_pending_whacks(struct state *st, err_t story); -extern void unpend(struct state *st); -extern void update_pending(struct state *os, struct state *ns); -extern void flush_pending_by_state(struct state *st); -extern void show_pending_phase2(const struct host_pair *hp, const struct state *st); - -extern void connection_discard(connection_t *c); - -/* A template connection's eroute can be eclipsed by - * either a %hold or an eroute for an instance iff - * the template is a /32 -> /32. This requires some special casing. - */ -#define eclipsable(sr) (subnetishost(&(sr)->this.client) && subnetishost(&(sr)->that.client)) -extern long eclipse_count; -extern connection_t *eclipsed(connection_t *c, struct spd_route **); - - -/* print connection status */ - -extern void show_connections_status(bool all, const char *name); -extern int connection_compare(const connection_t *ca - , const connection_t *cb); -extern void update_host_pair(const char *why, connection_t *c - , const ip_address *myaddr, u_int16_t myport - , const ip_address *hisaddr, u_int16_t hisport); - -#endif /* _CONNECTIONS_H */ diff --git a/src/pluto/constants.c b/src/pluto/constants.c deleted file mode 100644 index 73ec0bc54..000000000 --- a/src/pluto/constants.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* tables of names for values defined in constants.h - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Note that the array sizes are all specified; this is to enable range - * checking by code that only includes constants.h. - */ - -#include -#include -#include -#include - -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "packet.h" - -/* string naming compile-time options that have interop implications */ - -const char compile_time_interop_options[] = "" -#ifdef THREADS - " THREADS" -#endif -#ifdef SMARTCARD - " SMARTCARD" -#endif -#ifdef VENDORID - " VENDORID" -#endif -#ifdef CISCO_QUIRKS - " CISCO_QUIRKS" -#endif -#ifdef USE_KEYRR - " KEYRR" -#endif - ; - -/* version */ - -static const char *const version_name[] = { - "ISAKMP Version 1.0", -}; - -enum_names version_names = - { ISAKMP_MAJOR_VERSION< - -static const char *const rr_type_name[] = { - "T_A", /* 1 host address */ - "T_NS", /* 2 authoritative server */ - "T_MD", /* 3 mail destination */ - "T_MF", /* 4 mail forwarder */ - "T_CNAME", /* 5 canonical name */ - "T_SOA", /* 6 start of authority zone */ - "T_MB", /* 7 mailbox domain name */ - "T_MG", /* 8 mail group member */ - "T_MR", /* 9 mail rename name */ - "T_NULL", /* 10 null resource record */ - "T_WKS", /* 11 well known service */ - "T_PTR", /* 12 domain name pointer */ - "T_HINFO", /* 13 host information */ - "T_MINFO", /* 14 mailbox information */ - "T_MX", /* 15 mail routing information */ - "T_TXT", /* 16 text strings */ - "T_RP", /* 17 responsible person */ - "T_AFSDB", /* 18 AFS cell database */ - "T_X25", /* 19 X_25 calling address */ - "T_ISDN", /* 20 ISDN calling address */ - "T_RT", /* 21 router */ - "T_NSAP", /* 22 NSAP address */ - "T_NSAP_PTR", /* 23 reverse NSAP lookup (deprecated) */ - "T_SIG", /* 24 security signature */ - "T_KEY", /* 25 security key */ - "T_PX", /* 26 X.400 mail mapping */ - "T_GPOS", /* 27 geographical position (withdrawn) */ - "T_AAAA", /* 28 IP6 Address */ - "T_LOC", /* 29 Location Information */ - "T_NXT", /* 30 Next Valid Name in Zone */ - "T_EID", /* 31 Endpoint identifier */ - "T_NIMLOC", /* 32 Nimrod locator */ - "T_SRV", /* 33 Server selection */ - "T_ATMA", /* 34 ATM Address */ - "T_NAPTR", /* 35 Naming Authority PoinTeR */ - NULL -}; - -enum_names rr_type_names = { T_A, T_NAPTR, rr_type_name, NULL }; - -/* Query type values which do not appear in resource records */ -static const char *const rr_qtype_name[] = { - "T_IXFR", /* 251 incremental zone transfer */ - "T_AXFR", /* 252 transfer zone of authority */ - "T_MAILB", /* 253 transfer mailbox records */ - "T_MAILA", /* 254 transfer mail agent records */ - "T_ANY", /* 255 wildcard match */ - NULL -}; - -enum_names rr_qtype_names = { T_IXFR, T_ANY, rr_qtype_name, &rr_type_names }; - -static const char *const rr_class_name[] = { - "C_IN", /* 1 the arpa internet */ - NULL -}; - -enum_names rr_class_names = { C_IN, C_IN, rr_class_name, NULL }; - -#endif /* ADNS */ - -/* - * NAT-Traversal defines for nat_traveral type from nat_traversal.h - * - */ -const char *const natt_type_bitnames[] = { - "draft-ietf-ipsec-nat-t-ike-00/01", /* 0 */ - "draft-ietf-ipsec-nat-t-ike-02/03", - "RFC 3947", - "3", /* 3 */ - "4", "5", "6", "7", - "8", "9", "10", "11", - "12", "13", "14", "15", - "16", "17", "18", "19", - "20", "21", "22", "23", - "24", "25", "26", "27", - "28", "29", - "nat is behind me", - "nat is behind peer" -}; - -/* look up enum names in an enum_names */ - -const char* enum_name(enum_names *ed, unsigned long val) -{ - enum_names *p; - - for (p = ed; p != NULL; p = p->en_next_range) - { - if (p->en_first <= val && val <= p->en_last) - return p->en_names[val - p->en_first]; - } - return NULL; -} - -/* find or construct a string to describe an enum value - * Result may be in STATIC buffer! - */ -const char * -enum_show(enum_names *ed, unsigned long val) -{ - const char *p = enum_name(ed, val); - - if (p == NULL) - { - static char buf[12]; /* only one! I hope that it is big enough */ - - snprintf(buf, sizeof(buf), "%lu??", val); - p = buf; - } - return p; -} - - -static char bitnamesbuf[200]; /* only one! I hope that it is big enough! */ - -int -enum_search(enum_names *ed, const char *str) -{ - enum_names *p; - const char *ptr; - unsigned en; - - for (p = ed; p != NULL; p = p->en_next_range) - { - for (en = p->en_first; en <= p->en_last ;en++) - { - ptr = p->en_names[en - p->en_first]; - if (ptr == 0) - { - continue; - } - if (streq(ptr, str)) - { - return en; - } - } - } - return -1; -} - -/* construct a string to name the bits on in a set - * Result may be in STATIC buffer! - * Note: prettypolicy depends on internal details. - */ -const char* bitnamesof(const char *const table[], lset_t val) -{ - char *p = bitnamesbuf; - lset_t bit; - const char *const *tp; - - if (val == 0) - return "none"; - - for (tp = table, bit = 01; val != 0; bit <<= 1) - { - if (val & bit) - { - const char *n = *tp; - size_t nl; - - if (n == NULL || *n == '\0') - { - /* no name for this bit, so use hex */ - static char flagbuf[sizeof("0x80000000")]; - - snprintf(flagbuf, sizeof(flagbuf), "0x%llx", bit); - n = flagbuf; - } - - nl = strlen(n); - - if (p != bitnamesbuf && p < bitnamesbuf+sizeof(bitnamesbuf) - 1) - *p++ = '+'; - - if (bitnamesbuf+sizeof(bitnamesbuf) - p > (ptrdiff_t)nl) - { - strcpy(p, n); - p += nl; - } - val -= bit; - } - if (*tp != NULL) - tp++; /* move on, but not past end */ - } - *p = '\0'; - return bitnamesbuf; -} - -/* print a policy: like bitnamesof, but it also does the non-bitfields. - * Suppress the shunt and fail fields if 0. - */ -const char* prettypolicy(lset_t policy) -{ - const char *bn = bitnamesof(sa_policy_bit_names - , policy & ~(POLICY_SHUNT_MASK | POLICY_FAIL_MASK)); - size_t len; - lset_t shunt = (policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT; - lset_t fail = (policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT; - - if (bn != bitnamesbuf) - bitnamesbuf[0] = '\0'; - len = strlen(bitnamesbuf); - if (shunt != 0) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+%s" - , policy_shunt_names[shunt]); - len += strlen(bitnamesbuf + len); - } - if (fail != 0) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+failure%s" - , policy_fail_names[fail]); - len += strlen(bitnamesbuf + len); - } - if (NEVER_NEGOTIATE(policy)) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+NEVER_NEGOTIATE"); - len += strlen(bitnamesbuf + len); - } - return bitnamesbuf; -} - -/* test a set by seeing if all bits have names */ - -bool testset(const char *const table[], lset_t val) -{ - lset_t bit; - const char *const *tp; - - for (tp = table, bit = 01; val != 0; bit <<= 1, tp++) - { - const char *n = *tp; - - if (n == NULL || ((val & bit) && *n == '\0')) - return FALSE; - val &= ~bit; - } - return TRUE; -} - - -const char sparse_end[] = "end of sparse names"; - -/* look up enum names in a sparse_names */ -const char *sparse_name(sparse_names sd, unsigned long val) -{ - const struct sparse_name *p; - - for (p = sd; p->name != sparse_end; p++) - if (p->val == val) - return p->name; - return NULL; -} - -/* find or construct a string to describe an sparse value - * Result may be in STATIC buffer! - */ -const char* sparse_val_show(sparse_names sd, unsigned long val) -{ - const char *p = sparse_name(sd, val); - - if (p == NULL) - { - static char buf[12]; /* only one! I hope that it is big enough */ - - snprintf(buf, sizeof(buf), "%lu??", val); - p = buf; - } - return p; -} - -void init_constants(void) -{ - happy(anyaddr(AF_INET, &ipv4_any)); - happy(anyaddr(AF_INET6, &ipv6_any)); - - happy(addrtosubnet(&ipv4_any, &ipv4_wildcard)); - happy(addrtosubnet(&ipv6_any, &ipv6_wildcard)); - - happy(initsubnet(&ipv4_any, 0, '0', &ipv4_all)); - happy(initsubnet(&ipv6_any, 0, '0', &ipv6_all)); -} - -u_char secret_of_the_day[HASH_SIZE_SHA1]; - - diff --git a/src/pluto/constants.h b/src/pluto/constants.h deleted file mode 100644 index c931f1782..000000000 --- a/src/pluto/constants.h +++ /dev/null @@ -1,1099 +0,0 @@ -/* manifest constants - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CONSTANTS_H -#define _CONSTANTS_H - -#include - -#include - -#include -#include -#include - -extern const char compile_time_interop_options[]; - -extern void init_constants(void); - -/* - * NOTE:For debugging purposes, constants.c has tables to map numbers back to names. - * Any changes here should be reflected there. - */ - -/* Many routines return only success or failure, but wish to describe - * the failure in a message. We use the convention that they return - * a NULL on success and a pointer to constant string on failure. - * The fact that the string is a constant is limiting, but it - * avoids storage management issues: the recipient is allowed to assume - * that the string will live "long enough" (usually forever). - * defines err_t for this return type. - */ - -#define NULL_FD (-1) /* NULL file descriptor */ -#define dup_any(fd) ((fd) == NULL_FD? NULL_FD : dup(fd)) -#define close_any(fd) { if ((fd) != NULL_FD) { close(fd); (fd) = NULL_FD; } } - -/* set type with room for at least 64 elements for ALG opts (was 32 in stock FS) */ - -typedef unsigned long long lset_t; -#define LEMPTY 0ULL -#define LELEM(opt) (1ULL << (opt)) -#define LRANGE(lwb, upb) LRANGES(LELEM(lwb), LELEM(upb)) -#define LRANGES(first, last) (last - first + last) -#define LHAS(set, elem) ((LELEM(elem) & (set)) != LEMPTY) -#define LIN(subset, set) (((subset) & (set)) == (subset)) -#define LDISJOINT(a, b) (((a) & (b)) == LEMPTY) - -/* Control and lock pathnames */ -#ifndef IPSEC_PIDDIR -# define IPSEC_PIDDIR "/var/run" -#endif -#ifndef DEFAULT_CTLBASE -# define DEFAULT_CTLBASE IPSEC_PIDDIR "/pluto" -#endif - -#define CTL_SUFFIX ".ctl" /* for UNIX domain socket pathname */ -#define LOCK_SUFFIX ".pid" /* for pluto's lock */ -#define INFO_SUFFIX ".info" /* for UNIX domain socket for apps */ - -/* Routines to check and display values. - * - * An enum_names describes an enumeration. - * enum_name() returns the name of an enum value, or NULL if invalid. - * enum_show() is like enum_name, except it formats a numeric representation - * for any invalid value (in a static area!) - * - * bitnames() formats a display of a set of named bits (in a static area) - */ - -struct enum_names { - unsigned long en_first; /* first value in range */ - unsigned long en_last; /* last value in range (inclusive) */ - const char *const *en_names; - const struct enum_names *en_next_range; /* descriptor of next range */ -}; - -typedef const struct enum_names enum_names; - -extern const char *enum_name(enum_names *ed, unsigned long val); -extern const char *enum_show(enum_names *ed, unsigned long val); -extern int enum_search(enum_names *ed, const char *string); - -extern bool testset(const char *const table[], lset_t val); -extern const char *bitnamesof(const char *const table[], lset_t val); - -/* sparse_names is much like enum_names, except values are - * not known to be contiguous or ordered. - * The array of names is ended with one with the name sparse_end - * (this avoids having to reserve a value to signify the end). - * Often appropriate for enums defined by others. - */ -struct sparse_name { - unsigned long val; - const char *const name; -}; -typedef const struct sparse_name sparse_names[]; - -extern const char *sparse_name(sparse_names sd, unsigned long val); -extern const char *sparse_val_show(sparse_names sd, unsigned long val); -extern const char sparse_end[]; - -#define FULL_INET_ADDRESS_SIZE 6 - -/* limits on nonce sizes. See RFC2409 "The internet key exchange (IKE)" 5 */ -#define MINIMUM_NONCE_SIZE 8 /* bytes */ -#define DEFAULT_NONCE_SIZE 16 /* bytes */ -#define MAXIMUM_NONCE_SIZE 256 /* bytes */ - -#define COOKIE_SIZE 8 -#define MAX_ISAKMP_SPI_SIZE 16 - -#define DES_CBC_BLOCK_SIZE (64 / BITS_PER_BYTE) - -/* Maximum is required for SHA2_512 */ -#define MAX_DIGEST_LEN HASH_SIZE_SHA512 - -/* RFC 2404 "HMAC-SHA-1-96" section 3 */ -#define HMAC_SHA1_KEY_LEN HASH_SIZE_SHA1 - -/* RFC 2403 "HMAC-MD5-96" section 3 */ -#define HMAC_MD5_KEY_LEN HASH_SIZE_MD5 - -#define IKE_UDP_PORT 500 - -/* IPsec AH transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.3 - * and in http://www.iana.org/assignments/isakmp-registry - */ -enum ipsec_authentication_algo { - AH_NONE = 0, - AH_MD5 = 2, - AH_SHA = 3, - AH_DES = 4, - AH_SHA2_256 = 5, - AH_SHA2_384 = 6, - AH_SHA2_512 = 7, - AH_RIPEMD = 8, - AH_AES_XCBC_MAC = 9, - AH_RSA = 10, - AH_AES_128_GMAC = 11, - AH_AES_192_GMAC = 12, - AH_AES_256_GMAC = 13, - AH_SHA2_256_96 = 252 -}; - -extern enum_names ah_transform_names; - -/* IPsec ESP transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.4 - * and from http://www.iana.org/assignments/isakmp-registry - */ - -enum ipsec_cipher_algo { - ESP_NONE = 0, - ESP_DES_IV64 = 1, - ESP_DES = 2, - ESP_3DES = 3, - ESP_RC5 = 4, - ESP_IDEA = 5, - ESP_CAST = 6, - ESP_BLOWFISH = 7, - ESP_3IDEA = 8, - ESP_DES_IV32 = 9, - ESP_RC4 = 10, - ESP_NULL = 11, - ESP_AES = 12, - ESP_AES_CTR = 13, - ESP_AES_CCM_8 = 14, - ESP_AES_CCM_12 = 15, - ESP_AES_CCM_16 = 16, - ESP_UNASSIGNED_17 = 17, - ESP_AES_GCM_8 = 18, - ESP_AES_GCM_12 = 19, - ESP_AES_GCM_16 = 20, - ESP_SEED_CBC = 21, - ESP_CAMELLIA = 22, - ESP_AES_GMAC = 23, - ESP_SERPENT = 252, - ESP_TWOFISH = 253 -}; - -extern enum_names esp_transform_names; - -/* IPCOMP transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5 - * now defined in kernel/kernel_ipsec.h - */ - -extern enum_names ipcomp_transformid_names; - -/* Certificate type values - * RFC 2408 ISAKMP, chapter 3.9 - */ -enum ipsec_cert_type { - CERT_NONE= 0, - CERT_PKCS7_WRAPPED_X509= 1, - CERT_PGP= 2, - CERT_DNS_SIGNED_KEY= 3, - CERT_X509_SIGNATURE= 4, - CERT_X509_KEY_EXCHANGE= 5, - CERT_KERBEROS_TOKENS= 6, - CERT_CRL= 7, - CERT_ARL= 8, - CERT_SPKI= 9, - CERT_X509_ATTRIBUTE= 10, - CERT_RAW_RSA_KEY= 11 -}; - -/* RFC 2560 OCSP - certificate status */ - -typedef enum { - CERT_GOOD = 0, - CERT_REVOKED = 1, - CERT_UNKNOWN = 2, - CERT_UNDEFINED = 3 -} cert_status_t; - -/* RFC 3706 Dead Peer Detection */ - -extern enum_name_t *dpd_action_names; - -typedef enum { - DPD_ACTION_NONE = 0, - DPD_ACTION_CLEAR = 1, - DPD_ACTION_HOLD = 2, - DPD_ACTION_RESTART = 3, - DPD_ACTION_UNKNOWN = 4 -} dpd_action_t; - -/* Timer events */ - -extern enum_name_t *timer_event_names; - -enum event_type { - EVENT_NULL, /* non-event */ - EVENT_REINIT_SECRET, /* Refresh cookie secret */ - EVENT_SO_DISCARD, /* discard unfinished state object */ - EVENT_RETRANSMIT, /* Retransmit packet */ - EVENT_SA_REPLACE, /* SA replacement event */ - EVENT_SA_REPLACE_IF_USED, /* SA replacement event */ - EVENT_SA_EXPIRE, /* SA expiration event */ - EVENT_NAT_T_KEEPALIVE, /* NAT Traversal Keepalive */ - EVENT_DPD, /* dead peer detection */ - EVENT_DPD_TIMEOUT, /* dead peer detection timeout */ - EVENT_LOG_DAILY /* reset certain log events/stats */ -}; - -#define EVENT_REINIT_SECRET_DELAY 3600 /* 1 hour */ -#define EVENT_RETRANSMIT_DELAY_0 10 /* 10 seconds */ - -/* Misc. stuff */ - -#define MAXIMUM_RETRANSMISSIONS 2 -#define MAXIMUM_RETRANSMISSIONS_INITIAL 20 - -#define MAX_INPUT_UDP_SIZE 65536 -#define MAX_OUTPUT_UDP_SIZE 65536 - -/* Version numbers */ - -#define ISAKMP_MAJOR_VERSION 0x1 -#define ISAKMP_MINOR_VERSION 0x0 - -extern enum_names version_names; - -/* Domain of Interpretation */ - -extern enum_names doi_names; - -#define ISAKMP_DOI_ISAKMP 0 -#define ISAKMP_DOI_IPSEC 1 - -/* IPsec DOI things */ - -#define IPSEC_DOI_SITUATION_LENGTH 4 -#define IPSEC_DOI_LDI_LENGTH 4 -#define IPSEC_DOI_SPI_SIZE 4 - -/* SPI value 0 is invalid and values 1-255 are reserved to IANA. - * ESP: RFC 2402 2.4; AH: RFC 2406 2.1 - * IPComp RFC 2393 substitutes a CPI in the place of an SPI. - * see also draft-shacham-ippcp-rfc2393bis-05.txt. - * We (FreeS/WAN) reserve 0x100 to 0xFFF for manual keying, so - * Pluto won't generate these values. - */ -#define IPSEC_DOI_SPI_MIN 0x100 -#define IPSEC_DOI_SPI_OUR_MIN 0x1000 - -/* debugging settings: a set of selections for reporting - * These would be more naturally situated in log.h, - * but they are shared with whack. - * IMPAIR_* actually change behaviour, usually badly, - * to aid in testing. Naturally, these are not included in ALL. - * - * NOTE: changes here must be done in concert with changes to DBGOPT_* - * in whack.c. A change to WHACK_MAGIC in whack.h will be required too. - */ -#ifdef DEBUG -extern const char *const debug_bit_names[]; -#endif - -#define DBG_RAW LELEM(0) /* raw packet I/O */ -#define DBG_CRYPT LELEM(1) /* encryption/decryption of messages */ -#define DBG_PARSING LELEM(2) /* show decoding of messages */ -#define DBG_EMITTING LELEM(3) /* show encoding of messages */ -#define DBG_CONTROL LELEM(4) /* control flow within Pluto */ -#define DBG_LIFECYCLE LELEM(5) /* SA lifecycle */ -#define DBG_KERNEL LELEM(6) /* messages to kernel */ -#define DBG_DNS LELEM(7) /* DNS activity */ -#define DBG_NATT LELEM(8) /* NAT-T */ -#define DBG_OPPO LELEM(9) /* opportunism */ -#define DBG_CONTROLMORE LELEM(10) /* more detailed debugging */ - -#define DBG_PRIVATE LELEM(11) /* private information: DANGER! */ - -#define IMPAIR0 12 /* first bit for IMPAIR_* */ - -#define IMPAIR_DELAY_ADNS_KEY_ANSWER LELEM(IMPAIR0+0) /* sleep before answering */ -#define IMPAIR_DELAY_ADNS_TXT_ANSWER LELEM(IMPAIR0+1) /* sleep before answering */ -#define IMPAIR_BUST_MI2 LELEM(IMPAIR0+2) /* make MI2 really large */ -#define IMPAIR_BUST_MR2 LELEM(IMPAIR0+3) /* make MI2 really large */ - -#define DBG_NONE 0 /* no options on, including impairments */ -#define DBG_ALL LRANGES(DBG_RAW, DBG_CONTROLMORE) /* all logging options on EXCEPT DBG_PRIVATE */ - -/* State of exchanges - * - * The name of the state describes the last message sent, not the - * message currently being input or output (except during retry). - * In effect, the state represents the last completed action. - * - * Messages are named [MQ][IR]n where - * - M stands for Main Mode (Phase 1); - * Q stands for Quick Mode (Phase 2) - * - I stands for Initiator; - * R stands for Responder - * - n, a digit, stands for the number of the message - * - * It would be more convenient if each state accepted a message - * and produced one. This is the case for states at the start - * or end of an exchange. To fix this, we pretend that there are - * MR0 and QR0 messages before the MI1 and QR1 messages. Similarly, - * we pretend that there are MR4 and QR2 messages. - * - * STATE_MAIN_R0 and STATE_QUICK_R0 are intermediate states (not - * retained between messages) representing the state that accepts the - * first message of an exchange has been read but not processed. - * - * state_microcode state_microcode_table in demux.c describes - * other important details. - */ - -extern enum_names state_names; -extern const char *const state_story[]; - -enum state_kind { - STATE_UNDEFINED, /* 0 -- most likely accident */ - - /* IKE states */ - - STATE_MAIN_R0, - STATE_MAIN_I1, - STATE_MAIN_R1, - STATE_MAIN_I2, - STATE_MAIN_R2, - STATE_MAIN_I3, - STATE_MAIN_R3, - STATE_MAIN_I4, - - STATE_QUICK_R0, - STATE_QUICK_I1, - STATE_QUICK_R1, - STATE_QUICK_I2, - STATE_QUICK_R2, - - STATE_INFO, - STATE_INFO_PROTECTED, - - /* XAUTH states */ - - STATE_XAUTH_I0, /* initiator state (client) */ - STATE_XAUTH_R1, /* responder state (server) */ - STATE_XAUTH_I1, - STATE_XAUTH_R2, - STATE_XAUTH_I2, - STATE_XAUTH_R3, - - /* Mode Config pull states */ - - STATE_MODE_CFG_R0, /* responder state (server) */ - STATE_MODE_CFG_I1, /* initiator state (client) */ - STATE_MODE_CFG_R1, - STATE_MODE_CFG_I2, - - /* Mode Config push states */ - - STATE_MODE_CFG_I0, /* initiator state (client) */ - STATE_MODE_CFG_R3, /* responder state (server) */ - STATE_MODE_CFG_I3, - STATE_MODE_CFG_R4, - - STATE_IKE_ROOF -}; - -#define STATE_IKE_FLOOR STATE_MAIN_R0 - -#define PHASE1_INITIATOR_STATES (LELEM(STATE_MAIN_I1) | LELEM(STATE_MAIN_I2) \ - | LELEM(STATE_MAIN_I3) | LELEM(STATE_MAIN_I4)) -#define ISAKMP_SA_ESTABLISHED_STATES ( \ - LELEM(STATE_MAIN_R3) | LELEM(STATE_MAIN_I4) \ - | LELEM(STATE_XAUTH_R1) | LELEM(STATE_XAUTH_R2) | LELEM(STATE_XAUTH_R3) \ - | LELEM(STATE_XAUTH_I1) | LELEM(STATE_XAUTH_I2) \ - | LELEM(STATE_MODE_CFG_I1) | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_I2) \ - | LELEM(STATE_MODE_CFG_R3) | LELEM(STATE_MODE_CFG_I3) | LELEM(STATE_MODE_CFG_R4)) - -#define IS_PHASE1(s) ((STATE_MAIN_R0 <= (s) && (s) <= STATE_MAIN_I4) \ - || (STATE_XAUTH_I0 <= (s) && (s) <= STATE_XAUTH_R3) \ - || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_R4)) - -#define IS_QUICK(s) (STATE_QUICK_R0 <= (s) && (s) <= STATE_QUICK_R2) -#define IS_ISAKMP_ENCRYPTED(s) (STATE_MAIN_I2 <= (s)) - -#define IS_ISAKMP_SA_ESTABLISHED(s) ( \ - (s) == STATE_MAIN_R3 \ - || (s) == STATE_MAIN_I4 \ - || (s) == STATE_XAUTH_I2 \ - || (s) == STATE_XAUTH_R3 \ - || (s) == STATE_MODE_CFG_R1 \ - || (s) == STATE_MODE_CFG_I2 \ - || (s) == STATE_MODE_CFG_I3 \ - || (s) == STATE_MODE_CFG_R4) - -#define IS_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_I2 || (s) == STATE_QUICK_R2) -#define IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_R1) - -/* kind of struct connection - * Ordered (mostly) by concreteness. Order is exploited. - */ - -extern enum_names connection_kind_names; - -enum connection_kind { - CK_GROUP, /* policy group: instantiates to template */ - CK_TEMPLATE, /* abstract connection, with wildcard */ - CK_PERMANENT, /* normal connection */ - CK_INSTANCE, /* instance of template, created for a particular attempt */ - CK_GOING_AWAY /* instance being deleted -- don't delete again */ -}; - - -/* routing status. - * Note: routing ignores source address, but erouting does not! - * Note: a connection can only be routed if it is NEVER_NEGOTIATE - * or HAS_IPSEC_POLICY. - */ - -extern enum_names routing_story; - -/* note that this is assumed to be ordered! */ -enum routing_t { - RT_UNROUTED, /* unrouted */ - RT_UNROUTED_HOLD, /* unrouted, but HOLD shunt installed */ - RT_ROUTED_ECLIPSED, /* RT_ROUTED_PROSPECTIVE except bare HOLD or instance has eroute */ - RT_ROUTED_PROSPECTIVE, /* routed, and prospective shunt installed */ - RT_ROUTED_HOLD, /* routed, and HOLD shunt installed */ - RT_ROUTED_FAILURE, /* routed, and failure-context shunt installed */ - RT_ROUTED_TUNNEL, /* routed, and erouted to an IPSEC SA group */ - RT_UNROUTED_KEYED /* keyed, but not routed, on purpose */ -}; - -#define routed(rs) ((rs) > RT_UNROUTED_HOLD) -#define erouted(rs) ((rs) != RT_UNROUTED) -#define shunt_erouted(rs) (erouted(rs) && (rs) != RT_ROUTED_TUNNEL) - -/* Payload types - * RFC2408 Internet Security Association and Key Management Protocol (ISAKMP) - * section 3.1 - * - * RESERVED 14-127 - * Private USE 128-255 - */ - -extern enum_names payload_names; -extern const char *const payload_name[]; - -#define ISAKMP_NEXT_NONE 0 /* No other payload following */ -#define ISAKMP_NEXT_SA 1 /* Security Association */ -#define ISAKMP_NEXT_P 2 /* Proposal */ -#define ISAKMP_NEXT_T 3 /* Transform */ -#define ISAKMP_NEXT_KE 4 /* Key Exchange */ -#define ISAKMP_NEXT_ID 5 /* Identification */ -#define ISAKMP_NEXT_CERT 6 /* Certificate */ -#define ISAKMP_NEXT_CR 7 /* Certificate Request */ -#define ISAKMP_NEXT_HASH 8 /* Hash */ -#define ISAKMP_NEXT_SIG 9 /* Signature */ -#define ISAKMP_NEXT_NONCE 10 /* Nonce */ -#define ISAKMP_NEXT_N 11 /* Notification */ -#define ISAKMP_NEXT_D 12 /* Delete */ -#define ISAKMP_NEXT_VID 13 /* Vendor ID */ -#define ISAKMP_NEXT_ATTR 14 /* Mode config Attribute */ - -#define ISAKMP_NEXT_NATD_RFC 20 /* NAT-Traversal: NAT-D (rfc) */ -#define ISAKMP_NEXT_NATOA_RFC 21 /* NAT-Traversal: NAT-OA (rfc) */ -#define ISAKMP_NEXT_ROOF 22 /* roof on payload types */ - -#define ISAKMP_NEXT_NATD_DRAFTS 130 /* NAT-Traversal: NAT-D (drafts) */ -#define ISAKMP_NEXT_NATOA_DRAFTS 131 /* NAT-Traversal: NAT-OA (drafts) */ - -/* These values are to be used within the Type field of an Attribute (14) - * ISAKMP payload. - */ -#define ISAKMP_CFG_REQUEST 1 -#define ISAKMP_CFG_REPLY 2 -#define ISAKMP_CFG_SET 3 -#define ISAKMP_CFG_ACK 4 - -extern enum_names attr_msg_type_names; - -extern enum_names modecfg_attr_names; - -/* XAUTH authentication types */ -#define XAUTH_TYPE_GENERIC 0 -#define XAUTH_TYPE_CHAP 1 -#define XAUTH_TYPE_OTP 2 -#define XAUTH_TYPE_SKEY 3 - -/* Values for XAUTH_STATUS */ -#define XAUTH_STATUS_FAIL 0 -#define XAUTH_STATUS_OK 1 - -extern enum_names xauth_type_names; - -/* Exchange types - * RFC2408 "Internet Security Association and Key Management Protocol (ISAKMP)" - * section 3.1 - * - * ISAKMP Future Use 6 - 31 - * DOI Specific Use 32 - 239 - * Private Use 240 - 255 - * - * Note: draft-ietf-ipsec-dhless-enc-mode-00.txt Appendix A - * defines "DHless RSA Encryption" as 6. - */ - -extern enum_names exchange_names; - -#define ISAKMP_XCHG_NONE 0 -#define ISAKMP_XCHG_BASE 1 -#define ISAKMP_XCHG_IDPROT 2 /* ID Protection */ -#define ISAKMP_XCHG_AO 3 /* Authentication Only */ -#define ISAKMP_XCHG_AGGR 4 /* Aggressive */ -#define ISAKMP_XCHG_INFO 5 /* Informational */ -#define ISAKMP_XCHG_MODE_CFG 6 /* Mode Config */ - -/* Extra exchange types, defined by Oakley - * RFC2409 "The Internet Key Exchange (IKE)", near end of Appendix A - */ -#define ISAKMP_XCHG_QUICK 32 /* Oakley Quick Mode */ -#define ISAKMP_XCHG_NGRP 33 /* Oakley New Group Mode */ -/* added in draft-ietf-ipsec-ike-01.txt, near end of Appendix A */ -#define ISAKMP_XCHG_ACK_INFO 34 /* Oakley Acknowledged Informational */ - -/* Flag bits */ - -extern const char *const flag_bit_names[]; - -#define ISAKMP_FLAG_ENCRYPTION 0x1 -#define ISAKMP_FLAG_COMMIT 0x2 - -/* Situation definition for IPsec DOI */ - -extern const char *const sit_bit_names[]; - -#define SIT_IDENTITY_ONLY 0x01 -#define SIT_SECRECY 0x02 -#define SIT_INTEGRITY 0x04 - -/* Protocol IDs - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.1 - */ - -extern enum_names protocol_names; - -#define PROTO_ISAKMP 1 -#define PROTO_IPSEC_AH 2 -#define PROTO_IPSEC_ESP 3 -#define PROTO_IPCOMP 4 - -/* warning: trans_show uses enum_show, so same static buffer is used */ -#define trans_show(p, t) \ - ((p)==PROTO_IPSEC_AH ? enum_show(&ah_transformid_names, (t)) \ - : (p)==PROTO_IPSEC_ESP ? enum_show(&esp_transformid_names, (t)) \ - : (p)==PROTO_IPCOMP ? enum_show(&ipcomp_transformid_names, (t)) \ - : "??") - -#define KEY_IKE 1 - -extern enum_names isakmp_transformid_names; - -/* the following are from RFC 2393/draft-shacham-ippcp-rfc2393bis-05.txt 3.3 */ -typedef u_int16_t cpi_t; -#define IPCOMP_CPI_SIZE 2 -#define IPCOMP_FIRST_NEGOTIATED 256 -#define IPCOMP_LAST_NEGOTIATED 61439 - -/* Identification type values - * RFC 2407 The Internet IP security Domain of Interpretation for ISAKMP 4.6.2.1 - */ - -extern enum_names ident_names; -extern enum_names cert_type_names; - -extern enum_name_t *cert_policy_names; - -typedef enum certpolicy { - CERT_ALWAYS_SEND = 0, - CERT_SEND_IF_ASKED = 1, - CERT_NEVER_SEND = 2, - - CERT_YES_SEND = 3, /* synonym for CERT_ALWAYS_SEND */ - CERT_NO_SEND = 4 /* synonym for CERT_NEVER_SEND */ -} certpolicy_t; - -/* Policies for establishing an SA - * - * These are used to specify attributes (eg. encryption) and techniques - * (eg PFS) for an SA. - * Note: certain CD_ definitions in whack.c parallel these -- keep them - * in sync! - */ - -extern const char *const sa_policy_bit_names[]; -extern const char *prettypolicy(lset_t policy); - -/* ISAKMP auth techniques (none means never negotiate) */ -#define POLICY_PSK LELEM(0) -#define POLICY_PUBKEY LELEM(1) - -#define POLICY_ISAKMP_SHIFT 0 /* log2(POLICY_PSK) */ -#define POLICY_ID_AUTH_MASK (POLICY_PSK | POLICY_PUBKEY | POLICY_XAUTH_PSK | POLICY_XAUTH_RSASIG) -#define POLICY_ISAKMP_MASK POLICY_ID_AUTH_MASK /* all so far */ - -/* Quick Mode (IPSEC) attributes */ -#define POLICY_ENCRYPT LELEM(2) /* must be first of IPSEC policies */ -#define POLICY_AUTHENTICATE LELEM(3) /* must be second */ -#define POLICY_COMPRESS LELEM(4) /* must be third */ -#define POLICY_TUNNEL LELEM(5) -#define POLICY_PFS LELEM(6) -#define POLICY_DISABLEARRIVALCHECK LELEM(7) /* suppress tunnel egress address checking */ - -#define POLICY_IPSEC_SHIFT 2 /* log2(POLICY_ENCRYPT) */ -#define POLICY_IPSEC_MASK LRANGES(POLICY_ENCRYPT, POLICY_DISABLEARRIVALCHECK) - -/* shunt attributes: what to do when routed without tunnel (2 bits) */ -#define POLICY_SHUNT_SHIFT 8 /* log2(POLICY_SHUNT_PASS) */ -#define POLICY_SHUNT_MASK (03ul << POLICY_SHUNT_SHIFT) - -#define POLICY_SHUNT_TRAP (0ul << POLICY_SHUNT_SHIFT) /* default: negotiate */ -#define POLICY_SHUNT_PASS (1ul << POLICY_SHUNT_SHIFT) -#define POLICY_SHUNT_DROP (2ul << POLICY_SHUNT_SHIFT) -#define POLICY_SHUNT_REJECT (3ul << POLICY_SHUNT_SHIFT) - -/* fail attributes: what to do with failed negotiation (2 bits) */ - -#define POLICY_FAIL_SHIFT 10 /* log2(POLICY_FAIL_PASS) */ -#define POLICY_FAIL_MASK (03ul << POLICY_FAIL_SHIFT) - -#define POLICY_FAIL_NONE (0ul << POLICY_FAIL_SHIFT) /* default */ -#define POLICY_FAIL_PASS (1ul << POLICY_FAIL_SHIFT) -#define POLICY_FAIL_DROP (2ul << POLICY_FAIL_SHIFT) -#define POLICY_FAIL_REJECT (3ul << POLICY_FAIL_SHIFT) - -/* connection policy - * Other policies could vary per state object. These live in connection. - */ -#define POLICY_DONT_REKEY LELEM(12) /* don't rekey state either Phase */ -#define POLICY_OPPO LELEM(13) /* is this opportunistic? */ -#define POLICY_GROUP LELEM(14) /* is this a group template? */ -#define POLICY_GROUTED LELEM(15) /* do we want this group routed? */ -#define POLICY_UP LELEM(16) /* do we want this up? */ -#define POLICY_MODECFG_PUSH LELEM(17) /* is modecfg pushed by server? */ -#define POLICY_XAUTH_PSK LELEM(18) /* do we support XAUTH????PreShared? */ -#define POLICY_XAUTH_RSASIG LELEM(19) /* do we support XAUTH????RSA? */ -#define POLICY_XAUTH_SERVER LELEM(20) /* are we an XAUTH server? */ -#define POLICY_DONT_REAUTH LELEM(21) /* don't reauthenticate on rekeying, IKEv2 only */ -#define POLICY_BEET LELEM(22) /* bound end2end tunnel, IKEv2 */ -#define POLICY_MOBIKE LELEM(23) /* enable MOBIKE for IKEv2 */ -#define POLICY_FORCE_ENCAP LELEM(24) /* force UDP encapsulation (IKEv2) */ -#define POLICY_PROXY LELEM(25) /* proxy transport mode (MIPv6) */ - -/* Any IPsec policy? If not, a connection description - * is only for ISAKMP SA, not IPSEC SA. (A pun, I admit.) - * Note: a connection can only be routed if it is NEVER_NEGOTIATE - * or HAS_IPSEC_POLICY. - */ -#define HAS_IPSEC_POLICY(p) (((p) & POLICY_IPSEC_MASK) != 0) - -/* Don't allow negotiation? */ -#define NEVER_NEGOTIATE(p) (LDISJOINT((p), POLICY_ID_AUTH_MASK)) - - -/* Oakley transform attributes - * draft-ietf-ipsec-ike-01.txt appendix A - */ - -extern enum_names oakley_attr_names; -extern const char *const oakley_attr_bit_names[]; - -#define OAKLEY_ENCRYPTION_ALGORITHM 1 -#define OAKLEY_HASH_ALGORITHM 2 -#define OAKLEY_AUTHENTICATION_METHOD 3 -#define OAKLEY_GROUP_DESCRIPTION 4 -#define OAKLEY_GROUP_TYPE 5 -#define OAKLEY_GROUP_PRIME 6 /* B/V */ -#define OAKLEY_GROUP_GENERATOR_ONE 7 /* B/V */ -#define OAKLEY_GROUP_GENERATOR_TWO 8 /* B/V */ -#define OAKLEY_GROUP_CURVE_A 9 /* B/V */ -#define OAKLEY_GROUP_CURVE_B 10 /* B/V */ -#define OAKLEY_LIFE_TYPE 11 -#define OAKLEY_LIFE_DURATION 12 /* B/V */ -#define OAKLEY_PRF 13 -#define OAKLEY_KEY_LENGTH 14 -#define OAKLEY_FIELD_SIZE 15 -#define OAKLEY_GROUP_ORDER 16 /* B/V */ -#define OAKLEY_BLOCK_SIZE 17 - -/* for each Oakley attribute, which enum_names describes its values? */ -extern enum_names *oakley_attr_val_descs[]; - -/* IPsec DOI attributes - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5 - */ - -extern enum_names ipsec_attr_names; - -#define SA_LIFE_TYPE 1 -#define SA_LIFE_DURATION 2 /* B/V */ -#define GROUP_DESCRIPTION 3 -#define ENCAPSULATION_MODE 4 -#define AUTH_ALGORITHM 5 -#define KEY_LENGTH 6 -#define KEY_ROUNDS 7 -#define COMPRESS_DICT_SIZE 8 -#define COMPRESS_PRIVATE_ALG 9 /* B/V */ - -/* for each IPsec attribute, which enum_names describes its values? */ -extern enum_names *ipsec_attr_val_descs[]; - -/* SA Lifetime Type attribute - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5 - * Default time specified in 4.5 - * - * There are two defaults for IPSEC SA lifetime, SA_LIFE_DURATION_DEFAULT, - * and PLUTO_SA_LIFE_DURATION_DEFAULT. - * SA_LIFE_DURATION_DEFAULT is specified in RFC2407 "The Internet IP - * Security Domain of Interpretation for ISAKMP" 4.5. It applies when - * an ISAKMP negotiation does not explicitly specify a life duration. - * PLUTO_SA_LIFE_DURATION_DEFAULT is specified in pluto(8). It applies - * when a connection description does not specify --ipseclifetime. - * The value of SA_LIFE_DURATION_MAXIMUM is our local policy. - */ - -extern enum_names sa_lifetime_names; - -#define SA_LIFE_TYPE_SECONDS 1 -#define SA_LIFE_TYPE_KBYTES 2 - -#define SA_LIFE_DURATION_DEFAULT 28800 /* eight hours (RFC2407 4.5) */ -#define PLUTO_SA_LIFE_DURATION_DEFAULT 3600 /* one hour (pluto(8)) */ -#define SA_LIFE_DURATION_MAXIMUM 86400 /* one day */ - -#define SA_REPLACEMENT_MARGIN_DEFAULT 540 /* (IPSEC & IKE) nine minutes */ -#define SA_REPLACEMENT_FUZZ_DEFAULT 100 /* (IPSEC & IKE) 100% of MARGIN */ -#define SA_REPLACEMENT_RETRIES_DEFAULT 3 /* (IPSEC & IKE) */ - -#define SA_LIFE_DURATION_K_DEFAULT 0xFFFFFFFFlu - -/* Encapsulation Mode attribute */ - -extern enum_names enc_mode_names; - -#define ENCAPSULATION_MODE_UNSPECIFIED 0 /* not legal -- used internally */ -#define ENCAPSULATION_MODE_TUNNEL 1 -#define ENCAPSULATION_MODE_TRANSPORT 2 - -#define ENCAPSULATION_MODE_UDP_TUNNEL_RFC 3 -#define ENCAPSULATION_MODE_UDP_TRANSPORT_RFC 4 - -#define ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS 61443 -#define ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS 61444 - -/* Auth Algorithm attribute */ - -extern enum_names auth_alg_names, extended_auth_alg_names; - -#define AUTH_ALGORITHM_NONE 0 /* our private designation */ -#define AUTH_ALGORITHM_HMAC_MD5 1 -#define AUTH_ALGORITHM_HMAC_SHA1 2 -#define AUTH_ALGORITHM_DES_MAC 3 -#define AUTH_ALGORITHM_KPDK 4 -#define AUTH_ALGORITHM_HMAC_SHA2_256 5 -#define AUTH_ALGORITHM_HMAC_SHA2_384 6 -#define AUTH_ALGORITHM_HMAC_SHA2_512 7 -#define AUTH_ALGORITHM_HMAC_RIPEMD 8 -#define AUTH_ALGORITHM_AES_XCBC_MAC 9 -#define AUTH_ALGORITHM_SIG_RSA 10 -#define AUTH_ALGORITHM_AES_128_GMAC 11 -#define AUTH_ALGORITHM_AES_192_GMAC 12 -#define AUTH_ALGORITHM_AES_256_GMAC 13 -#define AUTH_ALGORITHM_NULL 251 -#define AUTH_ALGORITHM_HMAC_SHA2_256_96 252 - -/* Oakley Lifetime Type attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * As far as I can see, there is not specification for - * OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT. This could lead to interop problems! - * For no particular reason, we chose three hours. - * The value of OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM is our local policy. - */ -extern enum_names oakley_lifetime_names; - -#define OAKLEY_LIFE_SECONDS 1 -#define OAKLEY_LIFE_KILOBYTES 2 - -#define OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT 10800 /* three hours */ -#define OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM 86400 /* one day */ - -/* Oakley PRF attribute (none defined) - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_prf_names; - -/* HMAC (see rfc2104.txt) */ - -#define HMAC_IPAD 0x36 -#define HMAC_OPAD 0x5C - -/* Oakley Encryption Algorithm attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry - */ - -extern enum_names oakley_enc_names; - -#define OAKLEY_DES_CBC 1 -#define OAKLEY_IDEA_CBC 2 -#define OAKLEY_BLOWFISH_CBC 3 -#define OAKLEY_RC5_R16_B64_CBC 4 -#define OAKLEY_3DES_CBC 5 -#define OAKLEY_CAST_CBC 6 -#define OAKLEY_AES_CBC 7 -#define OAKLEY_CAMELLIA_CBC 8 - -#define OAKLEY_MARS_CBC 65001 -#define OAKLEY_RC6_CBC 65002 -#define OAKLEY_ID_65003 65003 -#define OAKLEY_SERPENT_CBC 65004 -#define OAKLEY_TWOFISH_CBC 65005 - -#define OAKLEY_TWOFISH_CBC_SSH 65289 - -#define OAKLEY_ENCRYPT_MAX 65535 /* pretty useless :) */ - -/* Oakley Hash Algorithm attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry - */ - -extern enum_names oakley_hash_names; - -#define OAKLEY_MD5 1 -#define OAKLEY_SHA 2 -#define OAKLEY_TIGER 3 -#define OAKLEY_SHA2_256 4 -#define OAKLEY_SHA2_384 5 -#define OAKLEY_SHA2_512 6 - -#define OAKLEY_HASH_MAX 7 - -/* Oakley Authentication Method attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * Goofy Hybrid extensions from draft-ietf-ipsec-isakmp-hybrid-auth-05.txt - * Goofy XAUTH extensions from draft-ietf-ipsec-isakmp-xauth-06.txt - */ - -extern enum_names oakley_auth_names; - -#define OAKLEY_PRESHARED_KEY 1 -#define OAKLEY_DSS_SIG 2 -#define OAKLEY_RSA_SIG 3 -#define OAKLEY_RSA_ENC 4 -#define OAKLEY_RSA_ENC_REV 5 -#define OAKLEY_ELGAMAL_ENC 6 -#define OAKLEY_ELGAMAL_ENC_REV 7 -#define OAKLEY_ECDSA_SIG 8 -#define OAKLEY_ECDSA_256 9 -#define OAKLEY_ECDSA_384 10 -#define OAKLEY_ECDSA_521 11 - -#define OAKLEY_AUTH_ROOF 12 /* roof on auth values THAT WE SUPPORT */ - -#define HybridInitRSA 64221 -#define HybridRespRSA 64222 -#define HybridInitDSS 64223 -#define HybridRespDSS 64224 - -#define XAUTHInitPreShared 65001 -#define XAUTHRespPreShared 65002 -#define XAUTHInitDSS 65003 -#define XAUTHRespDSS 65004 -#define XAUTHInitRSA 65005 -#define XAUTHRespRSA 65006 -#define XAUTHInitRSAEncryption 65007 -#define XAUTHRespRSAEncryption 65008 -#define XAUTHInitRSARevisedEncryption 65009 -#define XAUTHRespRSARevisedEncryption 65010 - -/* Oakley Group Description attribute - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_group_names; - -/* you must also touch: constants.c, crypto.c */ - -/* Oakley Group Type attribute - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_group_type_names; - -#define OAKLEY_GROUP_TYPE_MODP 1 -#define OAKLEY_GROUP_TYPE_ECP 2 -#define OAKLEY_GROUP_TYPE_EC2N 3 - - -/* Notify messages -- error types - * See RFC2408 ISAKMP 3.14.1 - */ - -extern enum_names notification_names; -extern enum_names ipsec_notification_names; - -typedef enum { - ISAKMP_NOTHING_WRONG = 0, /* unofficial! */ - - ISAKMP_INVALID_PAYLOAD_TYPE = 1, - ISAKMP_DOI_NOT_SUPPORTED = 2, - ISAKMP_SITUATION_NOT_SUPPORTED = 3, - ISAKMP_INVALID_COOKIE = 4, - ISAKMP_INVALID_MAJOR_VERSION = 5, - ISAKMP_INVALID_MINOR_VERSION = 6, - ISAKMP_INVALID_EXCHANGE_TYPE = 7, - ISAKMP_INVALID_FLAGS = 8, - ISAKMP_INVALID_MESSAGE_ID = 9, - ISAKMP_INVALID_PROTOCOL_ID = 10, - ISAKMP_INVALID_SPI = 11, - ISAKMP_INVALID_TRANSFORM_ID = 12, - ISAKMP_ATTRIBUTES_NOT_SUPPORTED = 13, - ISAKMP_NO_PROPOSAL_CHOSEN = 14, - ISAKMP_BAD_PROPOSAL_SYNTAX = 15, - ISAKMP_PAYLOAD_MALFORMED = 16, - ISAKMP_INVALID_KEY_INFORMATION = 17, - ISAKMP_INVALID_ID_INFORMATION = 18, - ISAKMP_INVALID_CERT_ENCODING = 19, - ISAKMP_INVALID_CERTIFICATE = 20, - ISAKMP_CERT_TYPE_UNSUPPORTED = 21, - ISAKMP_INVALID_CERT_AUTHORITY = 22, - ISAKMP_INVALID_HASH_INFORMATION = 23, - ISAKMP_AUTHENTICATION_FAILED = 24, - ISAKMP_INVALID_SIGNATURE = 25, - ISAKMP_ADDRESS_NOTIFICATION = 26, - ISAKMP_NOTIFY_SA_LIFETIME = 27, - ISAKMP_CERTIFICATE_UNAVAILABLE = 28, - ISAKMP_UNSUPPORTED_EXCHANGE_TYPE = 29, - ISAKMP_UNEQUAL_PAYLOAD_LENGTHS = 30, - - /* ISAKMP status type */ - ISAKMP_CONNECTED = 16384, - - /* IPSEC DOI additions; status types (RFC2407 IPSEC DOI 4.6.3) - * These must be sent under the protection of an ISAKMP SA. - */ - IPSEC_RESPONDER_LIFETIME = 24576, - IPSEC_REPLAY_STATUS = 24577, - IPSEC_INITIAL_CONTACT = 24578, - - /* RFC 3706 DPD */ - R_U_THERE = 36136, - R_U_THERE_ACK = 36137, - - /* Juniper SRX private use */ - NS_NHTB_INFORM = 40001 - - } notification_t; - - -/* Public key algorithm number - * Same numbering as used in DNSsec - * See RFC 2535 DNSsec 3.2 The KEY Algorithm Number Specification. - * Also found in BIND 8.2.2 include/isc/dst.h as DST algorithm codes. - */ - -enum pubkey_alg -{ - PUBKEY_ALG_RSA = 1, - PUBKEY_ALG_DSA = 3, -}; - -/* Limits on size of RSA moduli. - * The upper bound matches that of DNSsec (see RFC 2537). - * The lower bound must be more than 11 octets for certain - * the encoding to work, but it must be much larger for any - * real security. For now, we require 512 bits. - */ - -#define RSA_MIN_OCTETS_RFC 12 - -#define RSA_MIN_OCTETS (512 / BITS_PER_BYTE) -#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits" - -#define RSA_MAX_OCTETS (8192 / BITS_PER_BYTE) -#define RSA_MAX_OCTETS_UGH "RSA modulus too large: more than 8192 bits" - -/* Note: RFC 2537 encoding adds a few bytes. If you use a small - * modulus like 3, the overhead is only 2 bytes - */ -#define RSA_MAX_ENCODING_BYTES (RSA_MAX_OCTETS + 2) - -/* socket address family info */ - -struct af_info -{ - int af; - const char *name; - size_t ia_sz; - size_t sa_sz; - int mask_cnt; - u_int8_t id_addr, id_subnet, id_range; - const ip_address *any; - const ip_subnet *none; /* 0.0.0.0/32 or IPv6 equivalent */ - const ip_subnet *all; /* 0.0.0.0/0 or IPv6 equivalent */ -}; - -extern const struct af_info - af_inet4_info, - af_inet6_info; - -extern const struct af_info *aftoinfo(int af); - -extern enum_names af_names; - -#define subnetisaddr(sn, a) (subnetishost(sn) && addrinsubnet((a), (sn))) -extern bool subnetisnone(const ip_subnet *sn); - -/* BIND enumerated types */ - -extern enum_names - rr_qtype_names, - rr_type_names, - rr_class_names; - -/* How authenticated is info that might have come from DNS? - * In order of increasing confidence. - */ -enum dns_auth_level { - DAL_UNSIGNED, /* AD in response, but no signature: no authentication */ - DAL_NOTSEC, /* no AD in response: authentication impossible */ - DAL_SIGNED, /* AD and signature in response: authentic */ - DAL_LOCAL /* locally provided (pretty good) */ -}; - -/* - * define a macro for use in error messages - */ - -#ifdef USE_KEYRR -#define RRNAME "TXT or KEY" -#else -#define RRNAME "TXT" -#endif - -/* natt traversal types */ -extern const char *const natt_type_bitnames[]; - -/* secret value for responder cookies */ -extern u_char secret_of_the_day[HASH_SIZE_SHA1]; - -#endif /* _CONSTANTS_H */ diff --git a/src/pluto/cookie.c b/src/pluto/cookie.c deleted file mode 100644 index 00c863f18..000000000 --- a/src/pluto/cookie.c +++ /dev/null @@ -1,73 +0,0 @@ -/* cookie generation/verification routines. - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "cookie.h" - -const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ - -/* Generate a cookie. - * First argument is true if we're to create an Initiator cookie. - * Length SHOULD be a multiple of sizeof(u_int32_t). - */ -void get_cookie(bool initiator, u_int8_t *cookie, int length, ip_address *addr) -{ - hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - u_char buffer[HASH_SIZE_SHA1]; - - do { - if (initiator) - { - rng_t *rng; - - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - rng->get_bytes(rng, length, cookie); - rng->destroy(rng); - } - else /* Responder cookie */ - { - chunk_t addr_chunk, secret_chunk, counter_chunk; - size_t addr_len; - static u_int32_t counter = 0; - unsigned char addr_buf[ - sizeof(union {struct in_addr A; struct in6_addr B;})]; - - addr_len = addrbytesof(addr, addr_buf, sizeof(addr_buf)); - addr_chunk = chunk_create(addr_buf, addr_len); - secret_chunk = chunk_create(secret_of_the_day, HASH_SIZE_SHA1); - counter++; - counter_chunk = chunk_create((void *) &counter, sizeof(counter)); - hasher->get_hash(hasher, addr_chunk, NULL); - hasher->get_hash(hasher, secret_chunk, NULL); - hasher->get_hash(hasher, counter_chunk, buffer); - memcpy(cookie, buffer, length); - } - } while (is_zero_cookie(cookie)); /* probably never loops */ - - hasher->destroy(hasher); -} diff --git a/src/pluto/cookie.h b/src/pluto/cookie.h deleted file mode 100644 index 809d66491..000000000 --- a/src/pluto/cookie.h +++ /dev/null @@ -1,22 +0,0 @@ -/* cookie generation/verification routines. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -extern const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ - -extern void get_cookie(bool initiator, u_int8_t *cookie, int length, - ip_address *addr); - -#define is_zero_cookie(cookie) all_zero((cookie), COOKIE_SIZE) diff --git a/src/pluto/crl.c b/src/pluto/crl.c deleted file mode 100644 index c49b09e19..000000000 --- a/src/pluto/crl.c +++ /dev/null @@ -1,541 +0,0 @@ -/* Support of X.509 certificate revocation lists (CRLs) - * Copyright (C) 2000-2009 Andreas Steffen - * - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "keys.h" -#include "whack.h" -#include "fetch.h" -#include "builder.h" - - -/* chained lists of X.509 crls */ - -static x509crl_t *x509crls = NULL; - -/** - * Get the X.509 CRL with a given issuer - */ -static x509crl_t* get_x509crl(identification_t *issuer, chunk_t keyid) -{ - x509crl_t *x509crl = x509crls; - x509crl_t *prev_crl = NULL; - - while (x509crl != NULL) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *crl_issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - - if ((keyid.ptr && authKeyID.ptr)? same_keyid(keyid, authKeyID) : - issuer->equals(issuer, crl_issuer)) - { - if (x509crl != x509crls) - { - /* bring the CRL up front */ - prev_crl->next = x509crl->next; - x509crl->next = x509crls; - x509crls = x509crl; - } - return x509crl; - } - prev_crl = x509crl; - x509crl = x509crl->next; - } - return NULL; -} - -/** - * Free the dynamic memory used to store CRLs - */ -void free_crl(x509crl_t *crl) -{ - DESTROY_IF(crl->crl); - crl->distributionPoints->destroy_function(crl->distributionPoints, free); - free(crl); -} - -static void free_first_crl(void) -{ - x509crl_t *crl = x509crls; - - x509crls = crl->next; - free_crl(crl); -} - -void free_crls(void) -{ - lock_crl_list("free_crls"); - - while (x509crls != NULL) - { - free_first_crl(); - } - - unlock_crl_list("free_crls"); -} - -/** - * Insert X.509 CRL into chained list - */ -bool insert_crl(x509crl_t *x509crl, char *crl_uri, bool cache_crl) -{ - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - cert_t *issuer_cert; - x509crl_t *oldcrl; - time_t now, nextUpdate; - bool valid_sig; - - /* add distribution point */ - add_distribution_point(x509crl->distributionPoints, crl_uri); - - lock_authcert_list("insert_crl"); - - /* get the issuer cacert */ - issuer_cert = get_authcert(issuer, authKeyID, X509_CA); - if (issuer_cert == NULL) - { - plog("crl issuer cacert not found"); - free_crl(x509crl); - unlock_authcert_list("insert_crl"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("crl issuer cacert found") - ) - - /* check the issuer's signature of the crl */ - valid_sig = cert_crl->issued_by(cert_crl, issuer_cert->cert); - unlock_authcert_list("insert_crl"); - - if (!valid_sig) - { - free_crl(x509crl); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("crl signature is valid") - ) - - /* note the current time */ - time(&now); - - lock_crl_list("insert_crl"); - oldcrl = get_x509crl(issuer, authKeyID); - - if (oldcrl != NULL) - { - certificate_t *old_cert_crl = oldcrl->crl; - - if (crl_is_newer((crl_t*)cert_crl, (crl_t*)old_cert_crl)) - { - /* keep any known CRL distribution points */ - add_distribution_points(x509crl->distributionPoints, - oldcrl->distributionPoints); - - /* now delete the old CRL */ - free_first_crl(); - DBG(DBG_CONTROL, - DBG_log("thisUpdate is newer - existing crl deleted") - ) - } - else - { - unlock_crl_list("insert_crls"); - DBG(DBG_CONTROL, - DBG_log("thisUpdate is not newer - existing crl not replaced"); - ) - free_crl(x509crl); - old_cert_crl->get_validity(old_cert_crl, &now, NULL, &nextUpdate); - return nextUpdate - now > 2*crl_check_interval; - } - } - - /* insert new CRL */ - x509crl->next = x509crls; - x509crls = x509crl; - - unlock_crl_list("insert_crl"); - - /* If crl caching is enabled then the crl is saved locally. - * Only http or ldap URIs are cached but not local file URIs. - * The CRL's authorityKeyIdentifier is used as a unique filename - */ - if (cache_crl && strncasecmp(crl_uri, "file", 4) != 0) - { - char buf[BUF_LEN]; - chunk_t hex, encoding; - - hex = chunk_to_hex(crl->get_authKeyIdentifier(crl), NULL, FALSE); - snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_PATH, hex.ptr); - free(hex.ptr); - - if (cert_crl->get_encoding(cert_crl, CERT_ASN1_DER, &encoding)) - { - chunk_write(encoding, buf, "crl", 022, TRUE); - free(encoding.ptr); - } - } - - /* is the fetched crl valid? */ - cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate); - return nextUpdate - now > 2*crl_check_interval; -} - -/** - * Loads CRLs - */ -void load_crls(void) -{ - struct dirent **filelist; - u_char buf[BUF_LEN]; - u_char *save_dir; - int n; - - /* change directory to specified path */ - save_dir = getcwd(buf, BUF_LEN); - if (chdir(CRL_PATH)) - { - plog("Could not change to directory '%s'", CRL_PATH); - } - else - { - plog("Changing to directory '%s'", CRL_PATH); - n = scandir(CRL_PATH, &filelist, file_select, alphasort); - - if (n < 0) - plog(" scandir() error"); - else - { - while (n--) - { - char *filename = filelist[n]->d_name; - x509crl_t *x509crl; - - x509crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, - CERT_PLUTO_CRL, - BUILD_FROM_FILE, filename, BUILD_END); - if (x509crl) - { - char crl_uri[BUF_LEN]; - - plog(" loaded crl from '%s'", filename); - snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename); - insert_crl(x509crl, crl_uri, FALSE); - } - free(filelist[n]); - } - free(filelist); - } - } - /* restore directory path */ - ignore_result(chdir(save_dir)); -} - - -/* Checks if the current certificate is revoked. It goes through the - * list of revoked certificates of the corresponding crl. Either the - * status CERT_GOOD or CERT_REVOKED is returned - */ -static cert_status_t check_revocation(crl_t *crl, chunk_t cert_serial, - time_t *revocationDate, - crl_reason_t *revocationReason) -{ - enumerator_t *enumerator; - cert_status_t status; - chunk_t serial; - - DBG(DBG_CONTROL, - DBG_log("serial number: %#B", &cert_serial) - ) - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - status = CERT_GOOD; - - enumerator = crl->create_enumerator(crl); - while (enumerator->enumerate(enumerator, &serial, - revocationDate, revocationReason)) - { - if (chunk_equals(serial, cert_serial)) - { - status = CERT_REVOKED; - break; - } - } - enumerator->destroy(enumerator); - return status; -} - -/* - * check if any crls are about to expire - */ -void check_crls(void) -{ - x509crl_t *x509crl; - time_t now, nextUpdate, time_left; - - lock_crl_list("check_crls"); - time(&now); - x509crl = x509crls; - - while (x509crl != NULL) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - - cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate); - time_left = nextUpdate - now; - - DBG(DBG_CONTROL, - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr) - { - DBG_log("authkey: %#B", &authKeyID); - } - DBG_log("%ld seconds left", time_left) - ) - if (time_left < 2*crl_check_interval) - { - fetch_req_t *req = build_crl_fetch_request(issuer, authKeyID, - x509crl->distributionPoints); - add_crl_fetch_request(req); - } - x509crl = x509crl->next; - } - unlock_crl_list("check_crls"); -} - -/* - * verify if a cert hasn't been revoked by a crl - */ -cert_status_t verify_by_crl(cert_t *cert, time_t *until, time_t *revocationDate, - crl_reason_t *revocationReason) -{ - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - x509crl_t *x509crl; - ca_info_t *ca; - enumerator_t *enumerator; - x509_cdp_t *cdp; - - ca = get_ca_info(issuer, authKeyID); - - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - - lock_crl_list("verify_by_crl"); - x509crl = get_x509crl(issuer, authKeyID); - - if (x509crl == NULL) - { - linked_list_t *crluris; - - unlock_crl_list("verify_by_crl"); - plog("crl not found"); - - crluris = linked_list_create(); - if (ca) - { - add_distribution_points(crluris, ca->crluris); - } - - enumerator = x509->create_crl_uri_enumerator(x509); - while (enumerator->enumerate(enumerator, &cdp)) - { - add_distribution_point(crluris, cdp->uri); - } - enumerator->destroy(enumerator); - - if (crluris->get_count(crluris) > 0) - { - fetch_req_t *req; - - req = build_crl_fetch_request(issuer, authKeyID, crluris); - crluris->destroy_function(crluris, free); - add_crl_fetch_request(req); - wake_fetch_thread("verify_by_crl"); - return CERT_UNKNOWN; - } - else - { - crluris->destroy(crluris); - return CERT_UNDEFINED; - } - } - else - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - cert_t *issuer_cert; - bool trusted, valid; - - DBG(DBG_CONTROL, - DBG_log("crl found") - ) - - if (ca) - { - add_distribution_points(x509crl->distributionPoints, ca->crluris); - } - - enumerator = x509->create_crl_uri_enumerator(x509); - while (enumerator->enumerate(enumerator, &cdp)) - { - add_distribution_point(x509crl->distributionPoints, cdp->uri); - } - enumerator->destroy(enumerator); - - lock_authcert_list("verify_by_crl"); - - issuer_cert = get_authcert(issuer, authKeyID, X509_CA); - trusted = issuer_cert ? cert_crl->issued_by(cert_crl, issuer_cert->cert) - : FALSE; - - unlock_authcert_list("verify_by_crl"); - - if (trusted) - { - cert_status_t status; - - DBG(DBG_CONTROL, - DBG_log("crl signature is valid") - ) - - /* return the expiration date */ - valid = cert_crl->get_validity(cert_crl, NULL, NULL, until); - - /* has the certificate been revoked? */ - status = check_revocation(crl, x509->get_serial(x509), revocationDate - , revocationReason); - - if (valid) - { - unlock_crl_list("verify_by_crl"); - DBG(DBG_CONTROL, - DBG_log("crl is valid: until %T", until, FALSE) - ) - } - else - { - fetch_req_t *req; - - DBG(DBG_CONTROL, - DBG_log("crl is stale: since %T", until, FALSE) - ) - - /* try to fetch a crl update */ - req = build_crl_fetch_request(issuer, authKeyID, - x509crl->distributionPoints); - unlock_crl_list("verify_by_crl"); - - add_crl_fetch_request(req); - wake_fetch_thread("verify_by_crl"); - } - return status; - } - else - { - unlock_crl_list("verify_by_crl"); - plog("crl signature is invalid"); - return CERT_UNKNOWN; - } - } -} - -/* - * list all X.509 crls in the chained list - */ -void list_crls(bool utc, bool strict) -{ - x509crl_t *x509crl; - - lock_crl_list("list_crls"); - x509crl = x509crls; - - if (x509crl) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 CRLs:"); - } - - while (x509crl) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - chunk_t serial, authKeyID; - time_t thisUpdate, nextUpdate; - u_int revoked = 0; - enumerator_t *enumerator; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " issuer: \"%Y\"", - cert_crl->get_issuer(cert_crl)); - serial = chunk_skip_zero(crl->get_serial(crl)); - if (serial.ptr) - { - whack_log(RC_COMMENT, " serial: %#B", &serial); - } - - /* count number of revoked certificates in CRL */ - enumerator = crl->create_enumerator(crl); - while (enumerator->enumerate(enumerator, NULL, NULL, NULL)) - { - revoked++; - } - enumerator->destroy(enumerator); - whack_log(RC_COMMENT, " revoked: %d certificates", revoked); - - list_distribution_points(x509crl->distributionPoints); - - cert_crl->get_validity(cert_crl, NULL, &thisUpdate, &nextUpdate); - whack_log(RC_COMMENT, " updates: this %T", &thisUpdate, utc); - whack_log(RC_COMMENT, " next %T %s", &nextUpdate, utc, - check_expiry(nextUpdate, CRL_WARNING_INTERVAL, strict)); - authKeyID = crl->get_authKeyIdentifier(crl); - if (authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); - } - - x509crl = x509crl->next; - } - unlock_crl_list("list_crls"); -} - diff --git a/src/pluto/crl.h b/src/pluto/crl.h deleted file mode 100644 index 43bafe145..000000000 --- a/src/pluto/crl.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Support of X.509 certificate revocation lists (CRLs) - * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "constants.h" - -#include -#include -#include - -/* storage structure for an X.509 CRL */ - -typedef struct x509crl x509crl_t; - -struct x509crl { - certificate_t *crl; - x509crl_t *next; - linked_list_t *distributionPoints; -}; - -/* apply a strict CRL policy - * flag set in plutomain.c and used in ipsec_doi.c and rcv_whack.c - */ -extern bool strict_crl_policy; - -/* - * cache the retrieved CRLs by storing them locally as a file - */ -extern bool cache_crls; - -/* - * check periodically for expired crls - */ -extern long crl_check_interval; -extern void load_crls(void); -extern void check_crls(void); -extern bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl); -extern cert_status_t verify_by_crl(cert_t *cert, time_t *until, - time_t *revocationDate, - crl_reason_t *revocationReason); -extern void list_crls(bool utc, bool strict); -extern void free_crls(void); -extern void free_crl(x509crl_t *crl); diff --git a/src/pluto/crypto.c b/src/pluto/crypto.c deleted file mode 100644 index a4f678222..000000000 --- a/src/pluto/crypto.c +++ /dev/null @@ -1,698 +0,0 @@ -/* crypto interfaces - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2007-2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "constants.h" -#include "defs.h" -#include "crypto.h" -#include "log.h" - -static struct encrypt_desc encrypt_desc_3des = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_3DES_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: DES_BLOCK_SIZE, - keydeflen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keyminlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keymaxlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, -}; - -#define AES_KEY_MIN_LEN 128 -#define AES_KEY_DEF_LEN 128 -#define AES_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_aes = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_AES_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: AES_BLOCK_SIZE, - keyminlen: AES_KEY_MIN_LEN, - keydeflen: AES_KEY_DEF_LEN, - keymaxlen: AES_KEY_MAX_LEN, -}; - -#define CAMELLIA_KEY_MIN_LEN 128 -#define CAMELLIA_KEY_DEF_LEN 128 -#define CAMELLIA_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_camellia = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_CAMELLIA_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: CAMELLIA_BLOCK_SIZE, - keyminlen: CAMELLIA_KEY_MIN_LEN, - keydeflen: CAMELLIA_KEY_DEF_LEN, - keymaxlen: CAMELLIA_KEY_MAX_LEN, -}; - -#define BLOWFISH_KEY_MIN_LEN 128 -#define BLOWFISH_KEY_MAX_LEN 448 - -static struct encrypt_desc encrypt_desc_blowfish = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_BLOWFISH_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: BLOWFISH_BLOCK_SIZE, - keyminlen: BLOWFISH_KEY_MIN_LEN, - keydeflen: BLOWFISH_KEY_MIN_LEN, - keymaxlen: BLOWFISH_KEY_MAX_LEN, -}; - -#define SERPENT_KEY_MIN_LEN 128 -#define SERPENT_KEY_DEF_LEN 128 -#define SERPENT_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_serpent = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_SERPENT_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: SERPENT_BLOCK_SIZE, - keyminlen: SERPENT_KEY_MIN_LEN, - keydeflen: SERPENT_KEY_DEF_LEN, - keymaxlen: SERPENT_KEY_MAX_LEN, -}; - -#define TWOFISH_KEY_MIN_LEN 128 -#define TWOFISH_KEY_DEF_LEN 128 -#define TWOFISH_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_twofish = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: TWOFISH_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, -}; - -static struct encrypt_desc encrypt_desc_twofish_ssh = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC_SSH, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: TWOFISH_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, -}; - -static struct hash_desc hash_desc_md5 = -{ - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_MD5, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_MD5, -}; - -static struct hash_desc hash_desc_sha1 = -{ - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA1, -}; - -static struct hash_desc hash_desc_sha2_256 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_256, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA256, -}; - -static struct hash_desc hash_desc_sha2_384 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_384, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA384, -}; - -static struct hash_desc hash_desc_sha2_512 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_512, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA512, -}; - -const struct dh_desc unset_group = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_NONE, - plugin_name: NULL, - algo_next: NULL, - ke_size: 0 -}; - -static struct dh_desc dh_desc_modp_1024 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1024_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1024 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_1536 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1536_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1536 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_BIT, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_3072 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_3072_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 3072 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_4096 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_4096_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 4096 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_6144 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_6144_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 6144 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_8192 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_8192_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 8192 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_256 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_256_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*256 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_384 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_384_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*384 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_521 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_521_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*528 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_1024_160 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1024_160, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1024 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048_224 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_224, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048_256 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_256, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_192 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_192_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*192 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_224 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_224_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*224 / BITS_PER_BYTE -}; - -bool init_crypto(void) -{ - enumerator_t *enumerator; - encryption_algorithm_t encryption_alg; - hash_algorithm_t hash_alg; - diffie_hellman_group_t dh_group; - const char *plugin_name; - bool no_md5 = TRUE; - bool no_sha1 = TRUE; - - enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &hash_alg, &plugin_name)) - { - const struct hash_desc *desc; - - switch (hash_alg) - { - case HASH_SHA1: - desc = &hash_desc_sha1; - no_sha1 = FALSE; - break; - case HASH_SHA256: - desc = &hash_desc_sha2_256; - break; - case HASH_SHA384: - desc = &hash_desc_sha2_384; - break; - case HASH_SHA512: - desc = &hash_desc_sha2_512; - break; - case HASH_MD5: - desc = &hash_desc_md5; - no_md5 = FALSE; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - - if (no_sha1 || no_md5) - { - plog("pluto cannot run without a %s%s%s hasher", - (no_sha1) ? "SHA-1" : "", - (no_sha1 && no_md5) ? " and " : "", - (no_md5) ? "MD5" : ""); - return FALSE; - } - - enumerator = lib->crypto->create_crypter_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &encryption_alg, &plugin_name)) - { - const struct encrypt_desc *desc; - - switch (encryption_alg) - { - case ENCR_3DES: - desc = &encrypt_desc_3des; - break; - case ENCR_BLOWFISH: - desc = &encrypt_desc_blowfish; - break; - case ENCR_AES_CBC: - desc = &encrypt_desc_aes; - break; - case ENCR_CAMELLIA_CBC: - desc = &encrypt_desc_camellia; - break; - case ENCR_TWOFISH_CBC: - desc = &encrypt_desc_twofish; - ike_alg_add((struct ike_alg *)&encrypt_desc_twofish_ssh, - plugin_name); - break; - case ENCR_SERPENT_CBC: - desc = &encrypt_desc_serpent; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - - enumerator = lib->crypto->create_dh_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &dh_group, &plugin_name)) - { - const struct dh_desc *desc; - - switch (dh_group) - { - case MODP_1024_BIT: - desc = &dh_desc_modp_1024; - break; - case MODP_1536_BIT: - desc = &dh_desc_modp_1536; - break; - case MODP_2048_BIT: - desc = &dh_desc_modp_2048; - break; - case MODP_3072_BIT: - desc = &dh_desc_modp_3072; - break; - case MODP_4096_BIT: - desc = &dh_desc_modp_4096; - break; - case MODP_6144_BIT: - desc = &dh_desc_modp_6144; - break; - case MODP_8192_BIT: - desc = &dh_desc_modp_8192; - break; - case ECP_256_BIT: - desc = &dh_desc_ecp_256; - break; - case ECP_384_BIT: - desc = &dh_desc_ecp_384; - break; - case ECP_521_BIT: - desc = &dh_desc_ecp_521; - break; - case MODP_1024_160: - desc = &dh_desc_modp_1024_160; - break; - case MODP_2048_224: - desc = &dh_desc_modp_2048_224; - break; - case MODP_2048_256: - desc = &dh_desc_modp_2048_256; - break; - case ECP_192_BIT: - desc = &dh_desc_ecp_192; - break; - case ECP_224_BIT: - desc = &dh_desc_ecp_224; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - return TRUE; -} - -void free_crypto(void) -{ - /* currently nothing to do */ -} - -/** - * Converts IKEv1 encryption algorithm name to crypter name - */ -encryption_algorithm_t oakley_to_encryption_algorithm(int alg) -{ - switch (alg) - { - case OAKLEY_DES_CBC: - return ENCR_DES; - case OAKLEY_IDEA_CBC: - return ENCR_IDEA; - case OAKLEY_BLOWFISH_CBC: - return ENCR_BLOWFISH; - case OAKLEY_RC5_R16_B64_CBC: - return ENCR_RC5; - case OAKLEY_3DES_CBC: - return ENCR_3DES; - case OAKLEY_CAST_CBC: - return ENCR_CAST; - case OAKLEY_AES_CBC: - return ENCR_AES_CBC; - case OAKLEY_CAMELLIA_CBC: - return ENCR_CAMELLIA_CBC; - case OAKLEY_SERPENT_CBC: - return ENCR_SERPENT_CBC; - case OAKLEY_TWOFISH_CBC: - case OAKLEY_TWOFISH_CBC_SSH: - return ENCR_TWOFISH_CBC; - default: - return ENCR_UNDEFINED; - } -} - -/** - * Converts IKEv1 hash algorithm name to hasher name - */ -hash_algorithm_t oakley_to_hash_algorithm(int alg) -{ - switch (alg) - { - case OAKLEY_MD5: - return HASH_MD5; - case OAKLEY_SHA: - return HASH_SHA1; - case OAKLEY_SHA2_256: - return HASH_SHA256; - case OAKLEY_SHA2_384: - return HASH_SHA384; - case OAKLEY_SHA2_512: - return HASH_SHA512; - default: - return HASH_UNKNOWN; - } -} - -/** - * Converts IKEv1 hash algorithm name to IKEv2 prf name - */ -pseudo_random_function_t oakley_to_prf(int alg) -{ - switch (alg) - { - case OAKLEY_MD5: - return PRF_HMAC_MD5; - case OAKLEY_SHA: - return PRF_HMAC_SHA1; - case OAKLEY_SHA2_256: - return PRF_HMAC_SHA2_256; - case OAKLEY_SHA2_384: - return PRF_HMAC_SHA2_384; - case OAKLEY_SHA2_512: - return PRF_HMAC_SHA2_512; - default: - return PRF_UNDEFINED; - } -} - -/** - * Maps IKEv1 authentication method to IKEv2 signature scheme - */ -signature_scheme_t oakley_to_signature_scheme(int method) -{ - switch (method) - { - case OAKLEY_RSA_SIG: - case XAUTHInitRSA: - case XAUTHRespRSA: - return SIGN_RSA_EMSA_PKCS1_NULL; - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - return SIGN_ECDSA_WITH_NULL; - default: - return SIGN_UNKNOWN; - } -} - -/** - * Table to map IKEv2 encryption algorithms to IKEv1 (or IKEv1 ESP) and back - */ -struct { - encryption_algorithm_t alg; - int oakley; - int esp; -} encr_map[] = { - {ENCR_DES, OAKLEY_DES_CBC, ESP_DES }, - {ENCR_3DES, OAKLEY_3DES_CBC, ESP_3DES }, - {ENCR_RC5, OAKLEY_RC5_R16_B64_CBC, ESP_RC5 }, - {ENCR_IDEA, OAKLEY_IDEA_CBC, ESP_IDEA }, - {ENCR_CAST, OAKLEY_CAST_CBC, ESP_CAST }, - {ENCR_BLOWFISH, OAKLEY_BLOWFISH_CBC, ESP_BLOWFISH }, - {ENCR_AES_CBC, OAKLEY_AES_CBC, ESP_AES }, - {ENCR_CAMELLIA_CBC, OAKLEY_CAMELLIA_CBC, ESP_CAMELLIA }, - {ENCR_SERPENT_CBC, OAKLEY_SERPENT_CBC, ESP_SERPENT }, - {ENCR_TWOFISH_CBC, OAKLEY_TWOFISH_CBC, ESP_TWOFISH }, - {ENCR_NULL, 0, ESP_NULL }, - {ENCR_AES_CTR, 0, ESP_AES_CTR }, - {ENCR_AES_CCM_ICV8, 0, ESP_AES_CCM_8 }, - {ENCR_AES_CCM_ICV12, 0, ESP_AES_CCM_12}, - {ENCR_AES_CCM_ICV16, 0, ESP_AES_CCM_16}, - {ENCR_AES_GCM_ICV8, 0, ESP_AES_GCM_8 }, - {ENCR_AES_GCM_ICV12, 0, ESP_AES_GCM_12}, - {ENCR_AES_GCM_ICV16, 0, ESP_AES_GCM_16}, - {ENCR_NULL_AUTH_AES_GMAC, 0, ESP_AES_GMAC }, -}; - -/** - * Converts IKEv2 encryption to IKEv1 encryption algorithm - */ -int oakley_from_encryption_algorithm(encryption_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].alg == alg) - { - return encr_map[i].oakley; - } - } - return 0; -} - -/** - * Converts IKEv2 encryption to IKEv1 ESP encryption algorithm - */ -int esp_from_encryption_algorithm(encryption_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].alg == alg) - { - return encr_map[i].esp; - } - } - return 0; -} - -/** - * Converts IKEv1 ESP encryption to IKEv2 algorithm - */ -encryption_algorithm_t encryption_algorithm_from_esp(int esp) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].esp == esp) - { - return encr_map[i].alg; - } - } - return 0; -} - -/** - * Table to map IKEv2 integrity algorithms to IKEv1 (or IKEv1 ESP) and back - */ -struct { - integrity_algorithm_t alg; - int oakley; - int esp; -} auth_map[] = { - {AUTH_HMAC_MD5_96, OAKLEY_MD5, AUTH_ALGORITHM_HMAC_MD5 }, - {AUTH_HMAC_SHA1_96, OAKLEY_SHA, AUTH_ALGORITHM_HMAC_SHA1 }, - {AUTH_HMAC_SHA2_256_96, 0, AUTH_ALGORITHM_HMAC_SHA2_256_96}, - {AUTH_HMAC_SHA2_256_128, OAKLEY_SHA2_256, AUTH_ALGORITHM_HMAC_SHA2_256 }, - {AUTH_HMAC_SHA2_384_192, OAKLEY_SHA2_384, AUTH_ALGORITHM_HMAC_SHA2_384 }, - {AUTH_HMAC_SHA2_512_256, OAKLEY_SHA2_512, AUTH_ALGORITHM_HMAC_SHA2_512 }, - {AUTH_AES_XCBC_96, 0, AUTH_ALGORITHM_AES_XCBC_MAC }, - {AUTH_AES_128_GMAC, 0, AUTH_ALGORITHM_AES_128_GMAC }, - {AUTH_AES_192_GMAC, 0, AUTH_ALGORITHM_AES_192_GMAC }, - {AUTH_AES_256_GMAC, 0, AUTH_ALGORITHM_AES_256_GMAC }, -}; - - -/** - * Converts IKEv2 integrity to IKEv1 hash algorithm - */ -int oakley_from_integrity_algorithm(integrity_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].alg == alg) - { - return auth_map[i].oakley; - } - } - return 0; -} - -/** - * Converts IKEv2 integrity to IKEv1 ESP authentication algorithm - */ -int esp_from_integrity_algorithm(integrity_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].alg == alg) - { - return auth_map[i].esp; - } - } - return 0; -} - -/** - * Converts IKEv1 ESP authentication to IKEv2 integrity algorithm - */ -integrity_algorithm_t integrity_algorithm_from_esp(int esp) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].esp == esp) - { - return auth_map[i].alg; - } - } - return 0; -} - diff --git a/src/pluto/crypto.h b/src/pluto/crypto.h deleted file mode 100644 index 16ad12780..000000000 --- a/src/pluto/crypto.h +++ /dev/null @@ -1,64 +0,0 @@ -/* crypto interfaces - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998, 1999 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include "ike_alg.h" - -extern bool init_crypto(void); -extern void free_crypto(void); - -extern const struct dh_desc unset_group; /* magic signifier */ - -/* unification of cryptographic encoding/decoding algorithms - * The IV is taken from and returned to st->st_new_iv. - * This allows the old IV to be retained. - * Use update_iv to commit to the new IV (for example, once a packet has - * been validated). - */ - -#define MAX_OAKLEY_KEY_LEN0 (3 * DES_CBC_BLOCK_SIZE) -#define MAX_OAKLEY_KEY_LEN (256/BITS_PER_BYTE) - -struct state; /* forward declaration, dammit */ - -#define update_iv(st) memcpy((st)->st_iv, (st)->st_new_iv \ - , (st)->st_iv_len = (st)->st_new_iv_len) - -#define set_ph1_iv(st, iv) \ - passert((st)->st_ph1_iv_len <= sizeof((st)->st_ph1_iv)); \ - memcpy((st)->st_ph1_iv, (iv), (st)->st_ph1_iv_len); - -/* unification of cryptographic hashing mechanisms */ - -extern encryption_algorithm_t oakley_to_encryption_algorithm(int alg); -extern hash_algorithm_t oakley_to_hash_algorithm(int alg); -extern pseudo_random_function_t oakley_to_prf(int alg); -extern signature_scheme_t oakley_to_signature_scheme(int method); -extern int oakley_from_encryption_algorithm(encryption_algorithm_t alg); -extern int oakley_from_integrity_algorithm(integrity_algorithm_t alg); -extern int esp_from_encryption_algorithm(encryption_algorithm_t alg); -extern int esp_from_integrity_algorithm(integrity_algorithm_t alg); -extern encryption_algorithm_t encryption_algorithm_from_esp(int esp); -extern integrity_algorithm_t integrity_algorithm_from_esp(int esp); - diff --git a/src/pluto/db_ops.c b/src/pluto/db_ops.c deleted file mode 100644 index 547ea5f22..000000000 --- a/src/pluto/db_ops.c +++ /dev/null @@ -1,412 +0,0 @@ -/* Dynamic db (proposal, transforms, attributes) handling. - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * The stratedy is to have (full contained) struct db_prop in db_context - * pointing to ONE dynamically sizable transform vector (trans0). - * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0) - * in a "serialized" way (attributes storage is used in linear sequence for - * subsecuent transforms). - * - * Resizing for both trans0 and attrs0 is supported: - * - For trans0: quite simple, just allocate and copy trans. vector content - * also update trans_cur (by offset) - * - For attrs0: after allocating and copying attrs, I must rewrite each - * trans->attrs present in trans0; to achieve this, calculate - * attrs pointer offset (new minus old) and iterate over - * each transform "adding" this difference. - * also update attrs_cur (by offset) - * - * db_context structure: - * +---------------------+ - * | prop | - * | .protoid | - * | .trans | --+ - * | .trans_cnt | | - * +---------------------+ <-+ - * | trans0 | ----> { trans#1 | ... | trans#i | ... } - * +---------------------+ ^ - * | trans_cur | ----------------------' current transf. - * +---------------------+ - * | attrs0 | ----> { attr#1 | ... | attr#j | ... } - * +---------------------+ ^ - * | attrs_cur | ---------------------' current attr. - * +---------------------+ - * | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector - * +---------------------+ - * - * See testing examples at end for interface usage. - */ -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "state.h" -#include "packet.h" -#include "spdb.h" -#include "db_ops.h" -#include "log.h" -#include "whack.h" - -#include - -#ifdef NOT_YET -/* - * Allocator cache: - * Because of the single-threaded nature of pluto/spdb.c, - * alloc()/free() is exercised many times with very small - * lifetime objects. - * Just caching last object (currently it will select the - * largest) will avoid this allocation mas^Wperturbations - * - */ -struct db_ops_alloc_cache { - void *ptr; - int size; -}; -#endif - -#ifndef NO_DB_OPS_STATS -/* - * stats: do account for allocations - * displayed in db_ops_show_status() - */ -struct db_ops_stats { - int st_curr_cnt; /* current number of allocations */ - int st_total_cnt; /* total allocations so far */ - size_t st_maxsz; /* max. size requested */ -}; -#define DB_OPS_ZERO { 0, 0, 0}; -#define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}" -#define DB_OPS_STATS_STR(name) name "={%d,%d,%d} " -#define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (int)(st).st_maxsz -static struct db_ops_stats db_context_st = DB_OPS_ZERO; -static struct db_ops_stats db_trans_st = DB_OPS_ZERO; -static struct db_ops_stats db_attrs_st = DB_OPS_ZERO; -static __inline__ void *malloc_bytes_st(size_t size, struct db_ops_stats *st) -{ - void *ptr = malloc(size); - if (ptr) - { - st->st_curr_cnt++; - st->st_total_cnt++; - if (size > st->st_maxsz) st->st_maxsz=size; - } - return ptr; -} -#define ALLOC_BYTES_ST(z,st) malloc_bytes_st(z, &st); -#define PFREE_ST(p,st) do { st.st_curr_cnt--; free(p); } while (0); - -#else - -#define ALLOC_BYTES_ST(z,n) malloc(z); -#define PFREE_ST(p,n) free(p); - -#endif /* NO_DB_OPS_STATS */ -/* Initialize db object - * max_trans and max_attrs can be 0, will be dynamically expanded - * as a result of "add" operations - */ -int -db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs) -{ - ctx->trans0 = NULL; - ctx->attrs0 = NULL; - - if (max_trans > 0) { /* quite silly if not */ - ctx->trans0 = ALLOC_BYTES_ST ( sizeof(struct db_trans) * max_trans, - db_trans_st); - memset(ctx->trans0, '\0', sizeof(struct db_trans) * max_trans); - } - - if (max_attrs > 0) { /* quite silly if not */ - ctx->attrs0 = ALLOC_BYTES_ST (sizeof(struct db_attr) * max_attrs, - db_attrs_st); - memset(ctx->attrs0, '\0', sizeof(struct db_attr) * max_attrs); - } - - ctx->max_trans = max_trans; - ctx->max_attrs = max_attrs; - ctx->trans_cur = ctx->trans0; - ctx->attrs_cur = ctx->attrs0; - ctx->prop.protoid = protoid; - ctx->prop.trans = ctx->trans0; - ctx->prop.trans_cnt = 0; - return 0; -} - -/* Expand storage for transforms by number delta_trans */ -static int -db_trans_expand(struct db_context *ctx, int delta_trans) -{ - int ret = -1; - struct db_trans *new_trans, *old_trans; - int max_trans = ctx->max_trans + delta_trans; - int offset; - - old_trans = ctx->trans0; - new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans, - db_trans_st); - if (!new_trans) - goto out; - memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans)); - - /* update trans0 (obviously) */ - ctx->trans0 = ctx->prop.trans = new_trans; - /* update trans_cur (by offset) */ - offset = (char *)(new_trans) - (char *)(old_trans); - - { - char *cctx = (char *)(ctx->trans_cur); - - cctx += offset; - ctx->trans_cur = (struct db_trans *)cctx; - } - /* update elem count */ - ctx->max_trans = max_trans; - PFREE_ST(old_trans, db_trans_st); - ret = 0; -out: - return ret; -} -/* - * Expand storage for attributes by delta_attrs number AND - * rewrite trans->attr pointers - */ -static int -db_attrs_expand(struct db_context *ctx, int delta_attrs) -{ - int ret = -1; - struct db_attr *new_attrs, *old_attrs; - struct db_trans *t; - int ti; - int max_attrs = ctx->max_attrs + delta_attrs; - int offset; - - old_attrs = ctx->attrs0; - new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs, - db_attrs_st); - if (!new_attrs) - goto out; - - memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr)); - - /* update attrs0 and attrs_cur (obviously) */ - offset = (char *)(new_attrs) - (char *)(old_attrs); - - { - char *actx = (char *)(ctx->attrs0); - - actx += offset; - ctx->attrs0 = (struct db_attr *)actx; - - actx = (char *)ctx->attrs_cur; - actx += offset; - ctx->attrs_cur = (struct db_attr *)actx; - } - - /* for each transform, rewrite attrs pointer by offsetting it */ - for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) { - char *actx = (char *)(t->attrs); - - actx += offset; - t->attrs = (struct db_attr *)actx; - } - /* update elem count */ - ctx->max_attrs = max_attrs; - PFREE_ST(old_attrs, db_attrs_st); - ret = 0; -out: - return ret; -} -/* Allocate a new db object */ -struct db_context * -db_prop_new(u_int8_t protoid, int max_trans, int max_attrs) -{ - struct db_context *ctx; - ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), db_context_st); - if (!ctx) goto out; - - if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) { - PFREE_ST(ctx, db_context_st); - ctx=NULL; - } -out: - return ctx; -} -/* Free a db object */ -void -db_destroy(struct db_context *ctx) -{ - if (ctx->trans0) PFREE_ST(ctx->trans0, db_trans_st); - if (ctx->attrs0) PFREE_ST(ctx->attrs0, db_attrs_st); - PFREE_ST(ctx, db_context_st); -} -/* Start a new transform, expand trans0 is needed */ -int -db_trans_add(struct db_context *ctx, u_int8_t transid) -{ - /* skip incrementing current trans pointer the 1st time*/ - if (ctx->trans_cur && ctx->trans_cur->attr_cnt) - ctx->trans_cur++; - /* - * Strategy: if more space is needed, expand by - * /2 + 1 - * - * This happens to produce a "reasonable" sequence - * after few allocations, eg.: - * 0,1,2,4,8,13,20,31,47 - */ - if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) { - /* XXX:jjo if fails should shout and flag it */ - if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0) - return -1; - } - ctx->trans_cur->transid = transid; - ctx->trans_cur->attrs=ctx->attrs_cur; - ctx->trans_cur->attr_cnt = 0; - ctx->prop.trans_cnt++; - return 0; -} -/* Add attr copy to current transform, expanding attrs0 if needed */ -int -db_attr_add(struct db_context *ctx, const struct db_attr *a) -{ - /* - * Strategy: if more space is needed, expand by - * /2 + 1 - */ - if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) { - /* XXX:jjo if fails should shout and flag it */ - if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0) - return -1; - } - *ctx->attrs_cur++=*a; - ctx->trans_cur->attr_cnt++; - return 0; -} -/* Add attr copy (by value) to current transform, - * expanding attrs0 if needed, just calls db_attr_add(). - */ -int -db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val) -{ - struct db_attr attr; - attr.type = type; - attr.val = val; - return db_attr_add (ctx, &attr); -} -#ifndef NO_DB_OPS_STATS -int -db_ops_show_status(void) -{ - whack_log(RC_COMMENT, "stats " __FILE__ ": " - DB_OPS_STATS_DESC " :" - DB_OPS_STATS_STR("context") - DB_OPS_STATS_STR("trans") - DB_OPS_STATS_STR("attrs"), - DB_OPS_STATS_F(db_context_st), - DB_OPS_STATS_F(db_trans_st), - DB_OPS_STATS_F(db_attrs_st) - ); - return 0; -} -#endif /* NO_DB_OPS_STATS */ -/* - * From below to end just testing stuff .... - */ -#ifdef TEST -static void db_prop_print(struct db_prop *p) -{ - struct db_trans *t; - struct db_attr *a; - int ti, ai; - enum_names *n, *n_at, *n_av; - printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid)); - for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) { - switch( t->transid) { - case PROTO_ISAKMP: - n=&isakmp_transformid_names;break; - case PROTO_IPSEC_ESP: - n=&esp_transformid_names;break; - default: - continue; - } - printf(" transid=\"%s\"\n", - enum_name(n, t->transid)); - for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) { - int i; - switch( t->transid) { - case PROTO_ISAKMP: - n_at=&oakley_attr_names; - i=a->type|ISAKMP_ATTR_AF_TV; - n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK]; - break; - case PROTO_IPSEC_ESP: - n_at=&ipsec_attr_names; - i=a->type|ISAKMP_ATTR_AF_TV; - n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK]; - break; - default: - continue; - } - printf(" type=\"%s\" value=\"%s\"\n", - enum_name(n_at, i), - enum_name(n_av, a->val)); - } - } - -} -static void db_print(struct db_context *ctx) -{ - printf("trans_cur diff=%d, attrs_cur diff=%d\n", - ctx->trans_cur - ctx->trans0, - ctx->attrs_cur - ctx->attrs0); - db_prop_print(&ctx->prop); -} - -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no); -void abort(void); -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no) -{ - fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str); - abort(); /* exiting correctly doesn't always work */ -} -int main(void) { - struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0); - db_trans_add(ctx, KEY_IKE); - db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC); - db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5); - db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG); - db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024); - db_trans_add(ctx, KEY_IKE); - db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC); - db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5); - db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY); - db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536); - db_trans_add(ctx, ESP_3DES); - db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1); - db_print(ctx); - db_destroy(ctx); - return 0; -} -#endif diff --git a/src/pluto/db_ops.h b/src/pluto/db_ops.h deleted file mode 100644 index 464c245dd..000000000 --- a/src/pluto/db_ops.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Dynamic db (proposal, transforms, attributes) handling. - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DB_OPS_H -#define _DB_OPS_H - -/* - * Main db object, (quite proposal "oriented") - */ -#ifndef NO_DB_CONTEXT -struct db_context { - struct db_prop prop; /* proposal buffer (not pointer) */ - struct db_trans *trans0; /* transf. list, dynamically sized */ - struct db_trans *trans_cur; /* current transform ptr */ - struct db_attr *attrs0; /* attr. list, dynamically sized */ - struct db_attr *attrs_cur; /* current attribute ptr */ - int max_trans; /* size of trans list */ - int max_attrs; /* size of attrs list */ -}; -/* - * Allocate a new db object - */ -struct db_context * db_prop_new(u_int8_t protoid, int max_trans, int max_attrs); -/* Initialize object for proposal building */ -int db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs); -/* Free all resourses for this db */ -void db_destroy(struct db_context *ctx); - -/* Start a new transform */ -int db_trans_add(struct db_context *ctx, u_int8_t transid); -/* Add a new attribute by copying db_attr content */ -int db_attr_add(struct db_context *db_ctx, const struct db_attr *attr); -/* Add a new attribute by value */ -int db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val); - -/* Get proposal from db object */ -static __inline__ struct db_prop *db_prop_get(struct db_context *ctx) { - return &ctx->prop; -} -/* Show stats (allocation, etc) */ -#endif /* NO_DB_CONTEXT */ -int db_ops_show_status(void); -#endif /* _DB_OPS_H */ diff --git a/src/pluto/defs.c b/src/pluto/defs.c deleted file mode 100644 index 7f3a819de..000000000 --- a/src/pluto/defs.c +++ /dev/null @@ -1,145 +0,0 @@ -/* misc. universal things - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ - -bool -all_zero(const unsigned char *m, size_t len) -{ - size_t i; - - for (i = 0; i != len; i++) - if (m[i] != '\0') - return FALSE; - return TRUE; -} - -/* Note that there may be as many as six IDs that are temporary at - * one time before unsharing the two ends of a connection. So we need - * at least six temporary buffers for DER_ASN1_DN IDs. - * We rotate them. Be careful! - */ -#define MAX_BUF 10 - -char* -temporary_cyclic_buffer(void) -{ - static char buf[MAX_BUF][BUF_LEN]; /* MAX_BUF internal buffers */ - static int counter = 0; /* cyclic counter */ - - if (++counter == MAX_BUF) counter = 0; /* next internal buffer */ - return buf[counter]; /* assign temporary buffer */ -} - -/* concatenates two sub paths into a string with a maximum size of BUF_LEN - * use for temporary storage only - */ -char* concatenate_paths(char *a, char *b) -{ - char *c; - - if (*b == '/' || *b == '.') - return b; - - c = temporary_cyclic_buffer(); - snprintf(c, BUF_LEN, "%s/%s", a, b); - return c; -} - -/* moves a chunk to a memory position, chunk is freed afterwards - * position pointer is advanced after the insertion point - */ -void -mv_chunk(u_char **pos, chunk_t content) -{ - if (content.len > 0) - { - chunkcpy(*pos, content); - free(content.ptr); - } -} - -/* checks if the expiration date has been reached and - * warns during the warning_interval of the imminent - * expiry. strict=TRUE declares a fatal error, - * strict=FALSE issues a warning upon expiry. - */ -const char* -check_expiry(time_t expiration_date, int warning_interval, bool strict) -{ - time_t now, time_left; - - if (expiration_date == UNDEFINED_TIME) - return "ok (expires never)"; - - /* determine the current time */ - time(&now); - - time_left = (expiration_date - now); - if (time_left < 0) - return strict? "fatal (expired)" : "warning (expired)"; - - if (time_left > 86400*warning_interval) - return "ok"; - { - static char buf[35]; /* temporary storage */ - const char* unit = "second"; - - if (time_left > 172800) - { - time_left /= 86400; - unit = "day"; - } - else if (time_left > 7200) - { - time_left /= 3600; - unit = "hour"; - } - else if (time_left > 120) - { - time_left /= 60; - unit = "minute"; - } - snprintf(buf, 35, "warning (expires in %" PRIu64 " %s%s)", - (u_int64_t)time_left, unit, (time_left == 1) ? "" : "s"); - return buf; - } -} - - -/* - * Filter eliminating the directory entries '.' and '..' - */ -int -file_select(const struct dirent *entry) -{ - return strcmp(entry->d_name, "." ) && - strcmp(entry->d_name, ".."); -} - - diff --git a/src/pluto/defs.h b/src/pluto/defs.h deleted file mode 100644 index 532652e5b..000000000 --- a/src/pluto/defs.h +++ /dev/null @@ -1,79 +0,0 @@ -/* misc. universal things - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DEFS_H -#define _DEFS_H - -#include -#include - -#include - -#ifdef DEBUG -# define USED_BY_DEBUG /* ignore */ -#else -# define USED_BY_DEBUG UNUSED -#endif - -/* type of serial number of a state object - * Needed in connections.h and state.h; here to simplify dependencies. - */ -typedef unsigned long so_serial_t; -#define SOS_NOBODY 0 /* null serial number */ -#define SOS_FIRST 1 /* first normal serial number */ - -/* memory allocation */ - -#define clone_thing(orig) clalloc((void *)&(orig), sizeof(orig)) - -#define clone_str(str) \ - ((str) == NULL? NULL : strdup(str)) - -#define replace(p, q) \ - { free(p); (p) = (q); } - -#define chunkcpy(dst, chunk) \ - { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;} - -extern char* temporary_cyclic_buffer(void); -extern char* concatenate_paths(char *a, char *b); - -/* move a chunk to a memory position and free it after insertion */ -extern void mv_chunk(u_char **pos, chunk_t content); - -/* warns a predefined interval before expiry */ -extern const char* check_expiry(time_t expiration_date, - int warning_interval, bool strict); - -#define MAX_PROMPT_PASS_TRIALS 5 -#define PROMPT_PASS_LEN 64 - -/* filter eliminating the directory entries '.' and '..' */ -typedef struct dirent dirent_t; -extern int file_select(const dirent_t *entry); - -/* cleanly exit Pluto */ -extern void exit_pluto(int /*status*/) NEVER_RETURNS; - -/* zero all bytes */ -#define zero(x) memset((x), '\0', sizeof(*(x))) - -/* are all bytes 0? */ -extern bool all_zero(const unsigned char *m, size_t len); - -/* pad_up(n, m) is the amount to add to n to make it a multiple of m */ -#define pad_up(n, m) (((m) - 1) - (((n) + (m) - 1) % (m))) - -#endif /* _DEFS_H */ diff --git a/src/pluto/demux.c b/src/pluto/demux.c deleted file mode 100644 index 612e0813c..000000000 --- a/src/pluto/demux.c +++ /dev/null @@ -1,2527 +0,0 @@ -/* demultiplex incoming IKE messages - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* Ordering Constraints on Payloads - * - * rfc2409: The Internet Key Exchange (IKE) - * - * 5 Exchanges: - * "The SA payload MUST precede all other payloads in a phase 1 exchange." - * - * "Except where otherwise noted, there are no requirements for ISAKMP - * payloads in any message to be in any particular order." - * - * 5.3 Phase 1 Authenticated With a Revised Mode of Public Key Encryption: - * - * "If the HASH payload is sent it MUST be the first payload of the - * second message exchange and MUST be followed by the encrypted - * nonce. If the HASH payload is not sent, the first payload of the - * second message exchange MUST be the encrypted nonce." - * - * "Save the requirements on the location of the optional HASH payload - * and the mandatory nonce payload there are no further payload - * requirements. All payloads-- in whatever order-- following the - * encrypted nonce MUST be encrypted with Ke_i or Ke_r depending on the - * direction." - * - * 5.5 Phase 2 - Quick Mode - * - * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP - * header and a SA payload MUST immediately follow the HASH." - * [NOTE: there may be more than one SA payload, so this is not - * totally reasonable. Probably all SAs should be so constrained.] - * - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - * - * "With the exception of the HASH, SA, and the optional ID payloads, - * there are no payload ordering restrictions on Quick Mode." - */ - -/* Unfolding of Identity -- a central mystery - * - * This concerns Phase 1 identities, those of the IKE hosts. - * These are the only ones that are authenticated. Phase 2 - * identities are for IPsec SAs. - * - * There are three case of interest: - * - * (1) We initiate, based on a whack command specifying a Connection. - * We know the identity of the peer from the Connection. - * - * (2) (to be implemented) we initiate based on a flow from our client - * to some IP address. - * We immediately know one of the peer's client IP addresses from - * the flow. We must use this to figure out the peer's IP address - * and Id. To be solved. - * - * (3) We respond to an IKE negotiation. - * We immediately know the peer's IP address. - * We get an ID Payload in Main I2. - * - * Unfortunately, this is too late for a number of things: - * - the ISAKMP SA proposals have already been made (Main I1) - * AND one accepted (Main R1) - * - the SA includes a specification of the type of ID - * authentication so this is negotiated without being told the ID. - * - with Preshared Key authentication, Main I2 is encrypted - * using the key, so it cannot be decoded to reveal the ID - * without knowing (or guessing) which key to use. - * - * There are three reasonable choices here for the responder: - * + assume that the initiator is making wise offers since it - * knows the IDs involved. We can balk later (but not gracefully) - * when we find the actual initiator ID - * + attempt to infer identity by IP address. Again, we can balk - * when the true identity is revealed. Actually, it is enough - * to infer properties of the identity (eg. SA properties and - * PSK, if needed). - * + make all properties universal so discrimination based on - * identity isn't required. For example, always accept the same - * kinds of encryption. Accept Public Key Id authentication - * since the Initiator presumably has our public key and thinks - * we must have / can find his. This approach is weakest - * for preshared key since the actual key must be known to - * decrypt the Initiator's ID Payload. - * These choices can be blended. For example, a class of Identities - * can be inferred, sufficient to select a preshared key but not - * sufficient to infer a unique identity. - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* only used for belt-and-suspenders select call */ -#include /* only used for forensic poll call */ -#include -#include -#include -#include -#include - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) -# include /* for __u8, __u32 */ -# include -# include /* struct iovec */ -#endif - -#include - -#include "constants.h" -#include "defs.h" -#include "cookie.h" -#include "connections.h" -#include "state.h" -#include "packet.h" -#include "crypto.h" -#include "ike_alg.h" -#include "log.h" -#include "demux.h" /* needs packet.h */ -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "timer.h" -#include "whack.h" /* requires connections.h */ -#include "server.h" -#include "nat_traversal.h" -#include "vendor.h" -#include "modecfg.h" - -/* This file does basic header checking and demux of - * incoming packets. - */ - -/* forward declarations */ -static bool read_packet(struct msg_digest *md); -static void process_packet(struct msg_digest **mdp); - -/* Reply messages are built in this buffer. - * Only one state transition function can be using it at a time - * so suspended STFs must save and restore it. - * It could be an auto variable of complete_state_transition except for the fact - * that when a suspended STF resumes, its reply message buffer - * must be at the same location -- there are pointers into it. - */ -u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE]; - -/* state_microcode is a tuple of information parameterizing certain - * centralized processing of a packet. For example, it roughly - * specifies what payloads are expected in this message. - * The microcode is selected primarily based on the state. - * In Phase 1, the payload structure often depends on the - * authentication technique, so that too plays a part in selecting - * the state_microcode to use. - */ - -struct state_microcode { - enum state_kind state, next_state; - lset_t flags; - lset_t req_payloads; /* required payloads (allows just one) */ - lset_t opt_payloads; /* optional payloads (any mumber) */ - /* if not ISAKMP_NEXT_NONE, process_packet will emit HDR with this as np */ - u_int8_t first_out_payload; - enum event_type timeout_event; - state_transition_fn *processor; -}; - -/* State Microcode Flags, in several groups */ - -/* Oakley Auth values: to which auth values does this entry apply? - * Most entries will use SMF_ALL_AUTH because they apply to all. - * Note: SMF_ALL_AUTH matches 0 for those circumstances when no auth - * has been set. - */ -#define SMF_ALL_AUTH LRANGE(0, OAKLEY_AUTH_ROOF-1) -#define SMF_PSK_AUTH LELEM(OAKLEY_PRESHARED_KEY) -#define SMF_DS_AUTH (LELEM(OAKLEY_DSS_SIG) | LELEM(OAKLEY_RSA_SIG) | \ - LELEM(OAKLEY_ECDSA_SIG) | LELEM(OAKLEY_ECDSA_256) | \ - LELEM(OAKLEY_ECDSA_384) | LELEM(OAKLEY_ECDSA_521)) -#define SMF_PKE_AUTH (LELEM(OAKLEY_RSA_ENC) | LELEM(OAKLEY_ELGAMAL_ENC)) -#define SMF_RPKE_AUTH (LELEM(OAKLEY_RSA_ENC_REV) | LELEM(OAKLEY_ELGAMAL_ENC_REV)) - -/* misc flags */ - -#define SMF_INITIATOR LELEM(OAKLEY_AUTH_ROOF + 0) -#define SMF_FIRST_ENCRYPTED_INPUT LELEM(OAKLEY_AUTH_ROOF + 1) -#define SMF_INPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 2) -#define SMF_OUTPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 3) -#define SMF_RETRANSMIT_ON_DUPLICATE LELEM(OAKLEY_AUTH_ROOF + 4) - -#define SMF_ENCRYPTED (SMF_INPUT_ENCRYPTED | SMF_OUTPUT_ENCRYPTED) - -/* this state generates a reply message */ -#define SMF_REPLY LELEM(OAKLEY_AUTH_ROOF + 5) - -/* this state completes P1, so any pending P2 negotiations should start */ -#define SMF_RELEASE_PENDING_P2 LELEM(OAKLEY_AUTH_ROOF + 6) - -/* end of flags */ - - -static state_transition_fn /* forward declaration */ - unexpected, - informational; - -/* state_microcode_table is a table of all state_microcode tuples. - * It must be in order of state (the first element). - * After initialization, ike_microcode_index[s] points to the - * first entry in state_microcode_table for state s. - * Remember that each state name in Main or Quick Mode describes - * what has happened in the past, not what this message is. - */ - -static const struct state_microcode - *ike_microcode_index[STATE_IKE_ROOF - STATE_IKE_FLOOR]; - -static const struct state_microcode state_microcode_table[] = { -#define PT(n) ISAKMP_NEXT_##n -#define P(n) LELEM(PT(n)) - - /***** Phase 1 Main Mode *****/ - - /* No state for main_outI1: --> HDR, SA */ - - /* STATE_MAIN_R0: I1 --> R1 - * HDR, SA --> HDR, SA - */ - { STATE_MAIN_R0, STATE_MAIN_R1 - , SMF_ALL_AUTH | SMF_REPLY - , P(SA), P(VID) | P(CR), PT(NONE) - , EVENT_RETRANSMIT, main_inI1_outR1}, - - /* STATE_MAIN_I1: R1 --> I2 - * HDR, SA --> auth dependent - * SMF_PSK_AUTH, SMF_DS_AUTH: --> HDR, KE, Ni - * SMF_PKE_AUTH: - * --> HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r - * SMF_RPKE_AUTH: - * --> HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] - * Note: since we don't know auth at start, we cannot differentiate - * microcode entries based on it. - */ - { STATE_MAIN_I1, STATE_MAIN_I2 - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_REPLY - , P(SA), P(VID) | P(CR), PT(NONE) /* don't know yet */ - , EVENT_RETRANSMIT, main_inR1_outI2 }, - - /* STATE_MAIN_R1: I2 --> R2 - * SMF_PSK_AUTH, SMF_DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr - * SMF_PKE_AUTH: HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r - * --> HDR, KE, PubKey_i, PubKey_i - * SMF_RPKE_AUTH: - * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] - * --> HDR, PubKey_i, Ke_r, Ke_r - */ - { STATE_MAIN_R1, STATE_MAIN_R2 - , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY - , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(KE) - , EVENT_RETRANSMIT, main_inI2_outR2 }, - - { STATE_MAIN_R1, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_REPLY - , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR) | P(HASH), PT(KE) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - { STATE_MAIN_R1, STATE_UNDEFINED - , SMF_RPKE_AUTH | SMF_REPLY - , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR) | P(HASH) | P(CERT), PT(NONCE) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - /* for states from here on, output message must be encrypted */ - - /* STATE_MAIN_I2: R2 --> I3 - * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I - * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I - * SMF_PKE_AUTH: HDR, KE, PubKey_i, PubKey_i - * --> HDR*, HASH_I - * SMF_RPKE_AUTH: HDR, PubKey_i, Ke_r, Ke_r - * --> HDR*, HASH_I - */ - { STATE_MAIN_I2, STATE_MAIN_I3 - , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(ID) - , EVENT_RETRANSMIT, main_inR2_outI3 }, - - { STATE_MAIN_I2, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR), PT(HASH) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - { STATE_MAIN_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR), PT(HASH) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - /* for states from here on, input message must be encrypted */ - - /* STATE_MAIN_R2: I3 --> R3 - * SMF_PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R - * SMF_DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R - * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R - */ - { STATE_MAIN_R2, STATE_MAIN_R3 - , SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, main_inI3_outR3 }, - - { STATE_MAIN_R2, STATE_MAIN_R3 - , SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE) - , EVENT_SA_REPLACE, main_inI3_outR3 }, - - { STATE_MAIN_R2, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ }, - - /* STATE_MAIN_I3: R3 --> done - * SMF_PSK_AUTH: HDR*, IDr1, HASH_R --> done - * SMF_DS_AUTH: HDR*, IDr1, [ CERT, ] SIG_R --> done - * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_R --> done - * May initiate quick mode by calling quick_outI1 - */ - { STATE_MAIN_I3, STATE_MAIN_I4 - , SMF_PSK_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, main_inR3 }, - - { STATE_MAIN_I3, STATE_MAIN_I4 - , SMF_DS_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE) - , EVENT_SA_REPLACE, main_inR3 }, - - { STATE_MAIN_I3, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ }, - - /* STATE_MAIN_R3: can only get here due to packet loss */ - { STATE_MAIN_R3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE - , LEMPTY, LEMPTY - , PT(NONE), EVENT_NULL, unexpected }, - - /* STATE_MAIN_I4: can only get here due to packet loss */ - { STATE_MAIN_I4, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED - , LEMPTY, LEMPTY - , PT(NONE), EVENT_NULL, unexpected }, - - - /***** Phase 2 Quick Mode *****/ - - /* No state for quick_outI1: - * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ] - */ - - /* STATE_QUICK_R0: - * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] - * Installs inbound IPsec SAs. - * Because it may suspend for asynchronous DNS, first_out_payload - * is set to NONE to suppress early emission of HDR*. - * ??? it is legal to have multiple SAs, but we don't support it yet. - */ - { STATE_QUICK_R0, STATE_QUICK_R1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY - , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(NONE) - , EVENT_RETRANSMIT, quick_inI1_outR1 }, - - /* STATE_QUICK_I1: - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(3) - * Installs inbound and outbound IPsec SAs, routing, etc. - * ??? it is legal to have multiple SAs, but we don't support it yet. - */ - { STATE_QUICK_I1, STATE_QUICK_I2 - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_REPLY - , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(HASH) - , EVENT_SA_REPLACE, quick_inR1_outI2 }, - - /* STATE_QUICK_R1: HDR*, HASH(3) --> done - * Installs outbound IPsec SAs, routing, etc. - */ - { STATE_QUICK_R1, STATE_QUICK_R2 - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(HASH), LEMPTY, PT(NONE) - , EVENT_SA_REPLACE, quick_inI2 }, - - /* STATE_QUICK_I2: can only happen due to lost packet */ - { STATE_QUICK_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* STATE_QUICK_R2: can only happen due to lost packet */ - { STATE_QUICK_R2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - - /***** informational messages *****/ - - /* STATE_INFO: */ - { STATE_INFO, STATE_UNDEFINED - , SMF_ALL_AUTH - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, informational }, - - /* STATE_INFO_PROTECTED: */ - { STATE_INFO_PROTECTED, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(HASH), LEMPTY, PT(NONE) - , EVENT_NULL, informational }, - - /* XAUTH state transitions */ - { STATE_XAUTH_I0, STATE_XAUTH_I1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_RETRANSMIT, xauth_inI0 }, - - { STATE_XAUTH_R1, STATE_XAUTH_R2 - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_RETRANSMIT, xauth_inR1 }, - - { STATE_XAUTH_I1, STATE_XAUTH_I2 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, xauth_inI1 }, - - { STATE_XAUTH_R2, STATE_XAUTH_R3 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(NONE) - , EVENT_SA_REPLACE, xauth_inR2 }, - - { STATE_XAUTH_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_XAUTH_R3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* ModeCfg pull mode state transitions */ - - { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inR0 }, - - { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inI1 }, - - { STATE_MODE_CFG_R1, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_MODE_CFG_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* ModeCfg push mode state transitions */ - - { STATE_MODE_CFG_I0, STATE_MODE_CFG_I3 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inI0 }, - - { STATE_MODE_CFG_R3, STATE_MODE_CFG_R4 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inR3 }, - - { STATE_MODE_CFG_I3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_MODE_CFG_R4, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - -#undef P -#undef PT -}; - -void -init_demux(void) -{ - /* fill ike_microcode_index: - * make ike_microcode_index[s] point to first entry in - * state_microcode_table for state s (backward scan makes this easier). - * Check that table is in order -- catch coding errors. - * For what it's worth, this routine is idempotent. - */ - const struct state_microcode *t; - - for (t = &state_microcode_table[countof(state_microcode_table) - 1];;) - { - passert(STATE_IKE_FLOOR <= t->state && t->state < STATE_IKE_ROOF); - ike_microcode_index[t->state - STATE_IKE_FLOOR] = t; - if (t == state_microcode_table) - break; - t--; - passert(t[0].state <= t[1].state); - } -} - -/* Process any message on the MSG_ERRQUEUE - * - * This information is generated because of the IP_RECVERR socket option. - * The API is sparsely documented, and may be LINUX-only, and only on - * fairly recent versions at that (hence the conditional compilation). - * - * - ip(7) describes IP_RECVERR - * - recvmsg(2) describes MSG_ERRQUEUE - * - readv(2) describes iovec - * - cmsg(3) describes how to process auxiliary messages - * - * ??? we should link this message with one we've sent - * so that the diagnostic can refer to that negotiation. - * - * ??? how long can the messge be? - * - * ??? poll(2) has a very incomplete description of the POLL* events. - * We assume that POLLIN, POLLOUT, and POLLERR are all we need to deal with - * and that POLLERR will be on iff there is a MSG_ERRQUEUE message. - * - * We have to code around a couple of surprises: - * - * - Select can say that a socket is ready to read from, and - * yet a read will hang. It turns out that a message available on the - * MSG_ERRQUEUE will cause select to say something is pending, but - * a normal read will hang. poll(2) can tell when a MSG_ERRQUEUE - * message is pending. - * - * This is dealt with by calling check_msg_errqueue after select - * has indicated that there is something to read, but before the - * read is performed. check_msg_errqueue will return TRUE if there - * is something left to read. - * - * - A write to a socket may fail because there is a pending MSG_ERRQUEUE - * message, without there being anything wrong with the write. This - * makes for confusing diagnostics. - * - * To avoid this, we call check_msg_errqueue before a write. True, - * there is a race condition (a MSG_ERRQUEUE message might arrive - * between the check and the write), but we should eliminate many - * of the problematic events. To narrow the window, the poll(2) - * will await until an event happens (in the case or a write, - * POLLOUT; this should be benign for POLLIN). - */ - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) -static bool -check_msg_errqueue(const struct iface *ifp, short interest) -{ - struct pollfd pfd; - - pfd.fd = ifp->fd; - pfd.events = interest | POLLPRI | POLLOUT; - - while (pfd.revents = 0 - , poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLERR)) - { - u_int8_t buffer[3000]; /* hope that this is big enough */ - union - { - struct sockaddr sa; - struct sockaddr_in sa_in4; - struct sockaddr_in6 sa_in6; - } from; - - int from_len = sizeof(from); - - int packet_len; - - struct msghdr emh; - struct iovec eiov; - union { - /* force alignment (not documented as necessary) */ - struct cmsghdr ecms; - - /* how much space is enough? */ - unsigned char space[256]; - } ecms_buf; - - struct cmsghdr *cm; - char fromstr[sizeof(" for message to port 65536") + INET6_ADDRSTRLEN]; - struct state *sender = NULL; - - zero(&from.sa); - from_len = sizeof(from); - - emh.msg_name = &from.sa; /* ??? filled in? */ - emh.msg_namelen = sizeof(from); - emh.msg_iov = &eiov; - emh.msg_iovlen = 1; - emh.msg_control = &ecms_buf; - emh.msg_controllen = sizeof(ecms_buf); - emh.msg_flags = 0; - - eiov.iov_base = buffer; /* see readv(2) */ - eiov.iov_len = sizeof(buffer); - - packet_len = recvmsg(ifp->fd, &emh, MSG_ERRQUEUE); - - if (packet_len == -1) - { - log_errno((e, "recvmsg(,, MSG_ERRQUEUE) on %s failed in comm_handle" - , ifp->rname)); - break; - } - else if (packet_len == sizeof(buffer)) - { - plog("MSG_ERRQUEUE message longer than %lu bytes; truncated" - , (unsigned long) sizeof(buffer)); - } - else - { - sender = find_sender((size_t) packet_len, buffer); - } - - DBG_cond_dump(DBG_ALL, "rejected packet:\n", buffer, packet_len); - DBG_cond_dump(DBG_ALL, "control:\n", emh.msg_control, emh.msg_controllen); - /* ??? Andi Kleen and misc documentation - * suggests that name will have the original destination - * of the packet. We seem to see msg_namelen == 0. - * Andi says that this is a kernel bug and has fixed it. - * Perhaps in 2.2.18/2.4.0. - */ - passert(emh.msg_name == &from.sa); - DBG_cond_dump(DBG_ALL, "name:\n", emh.msg_name - , emh.msg_namelen); - - fromstr[0] = '\0'; /* usual case :-( */ - switch (from.sa.sa_family) - { - char as[INET6_ADDRSTRLEN]; - - case AF_INET: - if (emh.msg_namelen == sizeof(struct sockaddr_in)) - snprintf(fromstr, sizeof(fromstr) - , " for message to %s port %u" - , inet_ntop(from.sa.sa_family - , &from.sa_in4.sin_addr, as, sizeof(as)) - , ntohs(from.sa_in4.sin_port)); - break; - case AF_INET6: - if (emh.msg_namelen == sizeof(struct sockaddr_in6)) - snprintf(fromstr, sizeof(fromstr) - , " for message to %s port %u" - , inet_ntop(from.sa.sa_family - , &from.sa_in6.sin6_addr, as, sizeof(as)) - , ntohs(from.sa_in6.sin6_port)); - break; - } - - for (cm = CMSG_FIRSTHDR(&emh) - ; cm != NULL - ; cm = CMSG_NXTHDR(&emh,cm)) - { - if (cm->cmsg_level == SOL_IP - && cm->cmsg_type == IP_RECVERR) - { - /* ip(7) and recvmsg(2) specify: - * ee_origin is SO_EE_ORIGIN_ICMP for ICMP - * or SO_EE_ORIGIN_LOCAL for locally generated errors. - * ee_type and ee_code are from the ICMP header. - * ee_info is the discovered MTU for EMSGSIZE errors - * ee_data is not used. - * - * ??? recvmsg(2) says "SOCK_EE_OFFENDER" but - * means "SO_EE_OFFENDER". The OFFENDER is really - * the router that complained. As such, the port - * is meaningless. - */ - - /* ??? cmsg(3) claims that CMSG_DATA returns - * void *, but RFC 2292 and /usr/include/bits/socket.h - * say unsigned char *. The manual is being fixed. - */ - struct sock_extended_err *ee = (void *)CMSG_DATA(cm); - const char *offstr = "unspecified"; - char offstrspace[INET6_ADDRSTRLEN]; - char orname[50]; - - if (cm->cmsg_len > CMSG_LEN(sizeof(struct sock_extended_err))) - { - const struct sockaddr *offender = SO_EE_OFFENDER(ee); - - switch (offender->sa_family) - { - case AF_INET: - offstr = inet_ntop(offender->sa_family - , &((const struct sockaddr_in *)offender)->sin_addr - , offstrspace, sizeof(offstrspace)); - break; - case AF_INET6: - offstr = inet_ntop(offender->sa_family - , &((const struct sockaddr_in6 *)offender)->sin6_addr - , offstrspace, sizeof(offstrspace)); - break; - default: - offstr = "unknown"; - break; - } - } - - switch (ee->ee_origin) - { - case SO_EE_ORIGIN_NONE: - snprintf(orname, sizeof(orname), "none"); - break; - case SO_EE_ORIGIN_LOCAL: - snprintf(orname, sizeof(orname), "local"); - break; - case SO_EE_ORIGIN_ICMP: - snprintf(orname, sizeof(orname) - , "ICMP type %d code %d (not authenticated)" - , ee->ee_type, ee->ee_code - ); - break; - case SO_EE_ORIGIN_ICMP6: - snprintf(orname, sizeof(orname) - , "ICMP6 type %d code %d (not authenticated)" - , ee->ee_type, ee->ee_code - ); - break; - default: - snprintf(orname, sizeof(orname), "invalid origin %lu" - , (unsigned long) ee->ee_origin); - break; - } - - { - struct state *old_state = cur_state; - - cur_state = sender; - - /* note dirty trick to suppress ~ at start of format - * if we know what state to blame. - */ - if ((packet_len == 1) && (buffer[0] == 0xff) -#ifdef DEBUG - && ((cur_debugging & DBG_NATT) == 0) -#endif - ) { - /* don't log NAT-T keepalive related errors unless NATT debug is - * enabled - */ - } - else - plog((sender != NULL) + "~" - "ERROR: asynchronous network error report on %s" - "%s" - ", complainant %s" - ": %s" - " [errno %lu, origin %s" - /* ", pad %d, info %ld" */ - /* ", data %ld" */ - "]" - , ifp->rname - , fromstr - , offstr - , strerror(ee->ee_errno) - , (unsigned long) ee->ee_errno - , orname - /* , ee->ee_pad, (unsigned long)ee->ee_info */ - /* , (unsigned long)ee->ee_data */ - ); - cur_state = old_state; - } - } - else - { - /* .cmsg_len is a kernel_size_t(!), but the value - * certainly ought to fit in an unsigned long. - */ - plog("unknown cmsg: level %d, type %d, len %lu" - , cm->cmsg_level, cm->cmsg_type - , (unsigned long) cm->cmsg_len); - } - } - } - return (pfd.revents & interest) != 0; -} -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - -bool -send_packet(struct state *st, const char *where) -{ - connection_t *c = st->st_connection; - int port_buf; - bool err; - u_int8_t ike_pkt[MAX_OUTPUT_UDP_SIZE]; - u_int8_t *ptr; - unsigned long len; - - if (c->interface->ike_float && st->st_tpacket.len != 1) - { - if ((unsigned long) st->st_tpacket.len > (MAX_OUTPUT_UDP_SIZE-sizeof(u_int32_t))) - { - DBG_log("send_packet(): really too big"); - return FALSE; - } - ptr = ike_pkt; - /** Add Non-ESP marker **/ - memset(ike_pkt, 0, sizeof(u_int32_t)); - memcpy(ike_pkt + sizeof(u_int32_t), st->st_tpacket.ptr, - (unsigned long)st->st_tpacket.len); - len = (unsigned long) st->st_tpacket.len + sizeof(u_int32_t); - } - else - { - ptr = st->st_tpacket.ptr; - len = (unsigned long) st->st_tpacket.len; - } - - DBG(DBG_RAW, - { - DBG_log("sending %lu bytes for %s through %s to %s:%u:" - , (unsigned long) st->st_tpacket.len - , where - , c->interface->rname - , ip_str(&c->spd.that.host_addr) - , (unsigned)c->spd.that.host_port); - DBG_dump_chunk(NULL, st->st_tpacket); - }); - - /* XXX: Not very clean. We manipulate the port of the ip_address to - * have a port in the sockaddr*, but we retain the original port - * and restore it afterwards. - */ - - port_buf = portof(&c->spd.that.host_addr); - setportof(htons(c->spd.that.host_port), &c->spd.that.host_addr); - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) - (void) check_msg_errqueue(c->interface, POLLOUT); -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - - err = sendto(c->interface->fd - , ptr, len, 0 - , sockaddrof(&c->spd.that.host_addr) - , sockaddrlenof(&c->spd.that.host_addr)) != (ssize_t)len; - - /* restore port */ - setportof(port_buf, &c->spd.that.host_addr); - - if (err) - { - /* do not log NAT-T Keep Alive packets */ - if (streq(where, "NAT-T Keep Alive")) - return FALSE; - log_errno((e, "sendto on %s to %s:%u failed in %s" - , c->interface->rname - , ip_str(&c->spd.that.host_addr) - , (unsigned)c->spd.that.host_port - , where)); - return FALSE; - } - else - { - return TRUE; - } -} - -static stf_status -unexpected(struct msg_digest *md) -{ - loglog(RC_LOG_SERIOUS, "unexpected message received in state %s" - , enum_name(&state_names, md->st->st_state)); - return STF_IGNORE; -} - -static stf_status -informational(struct msg_digest *md UNUSED) -{ - struct payload_digest *const n_pld = md->chain[ISAKMP_NEXT_N]; - - /* If the Notification Payload is not null... */ - if (n_pld != NULL) - { - pb_stream *const n_pbs = &n_pld->pbs; - struct isakmp_notification *const n = &n_pld->payload.notification; - int disp_len; - char disp_buf[200]; - - /* Switch on Notification Type (enum) */ - switch (n->isan_type) - { - case R_U_THERE: - return dpd_inI_outR(md->st, n, n_pbs); - - case R_U_THERE_ACK: - return dpd_inR(md->st, n, n_pbs); - default: - if (pbs_left(n_pbs) >= sizeof(disp_buf)-1) - disp_len = sizeof(disp_buf)-1; - else - disp_len = pbs_left(n_pbs); - memcpy(disp_buf, n_pbs->cur, disp_len); - disp_buf[disp_len] = '\0'; - break; - } - } - return STF_IGNORE; -} - -/* message digest allocation and deallocation */ - -static struct msg_digest *md_pool = NULL; - -/* free_md_pool is only used to avoid leak reports */ -void -free_md_pool(void) -{ - for (;;) - { - struct msg_digest *md = md_pool; - - if (md == NULL) - break; - md_pool = md->next; - free(md); - } -} - -static struct msg_digest * -malloc_md(void) -{ - struct msg_digest *md = md_pool; - - /* convenient initializer: - * - all pointers NULL - * - .note = NOTHING_WRONG - * - .encrypted = FALSE - */ - static const struct msg_digest blank_md = { - .next = NULL, - }; - - if (md == NULL) - { - md = malloc_thing(struct msg_digest); - zero(md); - } - else - md_pool = md->next; - - *md = blank_md; - md->digest_roof = md->digest; - - /* note: although there may be multiple msg_digests at once - * (due to suspended state transitions), there is a single - * global reply_buffer. It will need to be saved and restored. - */ - init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - return md; -} - -void -release_md(struct msg_digest *md) -{ - chunk_free(&md->raw_packet); - free(md->packet_pbs.start); - md->packet_pbs.start = NULL; - md->next = md_pool; - md_pool = md; -} - -/* wrapper for read_packet and process_packet - * - * The main purpose of this wrapper is to factor out teardown code - * from the many return points in process_packet. This amounts to - * releasing the msg_digest and resetting global variables. - * - * When processing of a packet is suspended (STF_SUSPEND), - * process_packet sets md to NULL to prevent the msg_digest being freed. - * Someone else must ensure that msg_digest is freed eventually. - * - * read_packet is broken out to minimize the lifetime of the - * enormous input packet buffer, an auto. - */ -void -comm_handle(const struct iface *ifp) -{ - static struct msg_digest *md; - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) - /* Even though select(2) says that there is a message, - * it might only be a MSG_ERRQUEUE message. At least - * sometimes that leads to a hanging recvfrom. To avoid - * what appears to be a kernel bug, check_msg_errqueue - * uses poll(2) and tells us if there is anything for us - * to read. - * - * This is early enough that teardown isn't required: - * just return on failure. - */ - if (!check_msg_errqueue(ifp, POLLIN)) - return; /* no normal message to read */ -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - - md = malloc_md(); - md->iface = ifp; - - if (read_packet(md)) - process_packet(&md); - - if (md != NULL) - release_md(md); - - cur_state = NULL; - reset_cur_connection(); - cur_from = NULL; -} - -/* read the message. - * Since we don't know its size, we read it into - * an overly large buffer and then copy it to a - * new, properly sized buffer. - */ -static bool -read_packet(struct msg_digest *md) -{ - const struct iface *ifp = md->iface; - int packet_len; - u_int8_t *buffer; - u_int8_t *buffer_nat; - union - { - struct sockaddr sa; - struct sockaddr_in sa_in4; - struct sockaddr_in6 sa_in6; - } from; - int from_len = sizeof(from); - err_t from_ugh = NULL; - static const char undisclosed[] = "unknown source"; - - happy(anyaddr(addrtypeof(&ifp->addr), &md->sender)); - zero(&from.sa); - ioctl(ifp->fd, FIONREAD, &packet_len); - buffer = malloc(packet_len); - packet_len = recvfrom(ifp->fd, buffer, packet_len, 0 - , &from.sa, &from_len); - - /* First: digest the from address. - * We presume that nothing here disturbs errno. - */ - if (packet_len == -1 - && from_len == sizeof(from) - && all_zero((const void *)&from.sa, sizeof(from))) - { - /* "from" is untouched -- not set by recvfrom */ - from_ugh = undisclosed; - } - else if (from_len - < (int) (offsetof(struct sockaddr, sa_family) + sizeof(from.sa.sa_family))) - { - from_ugh = "truncated"; - } - else - { - const struct af_info *afi = aftoinfo(from.sa.sa_family); - - if (afi == NULL) - { - from_ugh = "unexpected Address Family"; - } - else if (from_len != (int)afi->sa_sz) - { - from_ugh = "wrong length"; - } - else - { - switch (from.sa.sa_family) - { - case AF_INET: - from_ugh = initaddr((void *) &from.sa_in4.sin_addr - , sizeof(from.sa_in4.sin_addr), AF_INET, &md->sender); - md->sender_port = ntohs(from.sa_in4.sin_port); - break; - case AF_INET6: - from_ugh = initaddr((void *) &from.sa_in6.sin6_addr - , sizeof(from.sa_in6.sin6_addr), AF_INET6, &md->sender); - md->sender_port = ntohs(from.sa_in6.sin6_port); - break; - } - } - } - - /* now we report any actual I/O error */ - if (packet_len == -1) - { - if (from_ugh == undisclosed - && errno == ECONNREFUSED) - { - /* Tone down scary message for vague event: - * We get "connection refused" in response to some - * datagram we sent, but we cannot tell which one. - */ - plog("some IKE message we sent has been rejected with ECONNREFUSED (kernel supplied no details)"); - } - else if (from_ugh != NULL) - { - log_errno((e, "recvfrom on %s failed; Pluto cannot decode source sockaddr in rejection: %s" - , ifp->rname, from_ugh)); - } - else - { - log_errno((e, "recvfrom on %s from %s:%u failed" - , ifp->rname - , ip_str(&md->sender), (unsigned)md->sender_port)); - } - free(buffer); - return FALSE; - } - else if (from_ugh != NULL) - { - plog("recvfrom on %s returned malformed source sockaddr: %s" - , ifp->rname, from_ugh); - free(buffer); - return FALSE; - } - cur_from = &md->sender; - cur_from_port = md->sender_port; - - if (ifp->ike_float == TRUE) - { - u_int32_t non_esp; - - if (packet_len < (int)sizeof(u_int32_t)) - { - plog("recvfrom %s:%u too small packet (%d)" - , ip_str(cur_from), (unsigned) cur_from_port, packet_len); - free(buffer); - return FALSE; - } - memcpy(&non_esp, buffer, sizeof(u_int32_t)); - if (non_esp != 0) - { - plog("recvfrom %s:%u has no Non-ESP marker" - , ip_str(cur_from), (unsigned) cur_from_port); - free(buffer); - return FALSE; - } - packet_len -= sizeof(u_int32_t); - buffer_nat = malloc(packet_len); - memcpy(buffer_nat, buffer + sizeof(u_int32_t), packet_len); - free(buffer); - buffer = buffer_nat; - } - - /* Clone actual message contents - * and set up md->packet_pbs to describe it. - */ - init_pbs(&md->packet_pbs, buffer, packet_len, "packet"); - - DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL, - { - DBG_log(BLANK_FORMAT); - DBG_log("*received %d bytes from %s:%u on %s" - , (int) pbs_room(&md->packet_pbs) - , ip_str(cur_from), (unsigned) cur_from_port - , ifp->rname); - }); - - DBG(DBG_RAW, - DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs))); - - if ((pbs_room(&md->packet_pbs)==1) && (md->packet_pbs.start[0]==0xff)) - { - /** - * NAT-T Keep-alive packets should be discarded by kernel ESPinUDP - * layer. But bogus keep-alive packets (sent with a non-esp marker) - * can reach this point. Complain and discard them. - */ - DBG(DBG_NATT, - DBG_log("NAT-T keep-alive (bogus ?) should not reach this point. " - "Ignored. Sender: %s:%u", ip_str(cur_from), - (unsigned) cur_from_port); - ) - return FALSE; - } - -#define IKEV2_VERSION_OFFSET 17 -#define IKEV2_VERSION 0x20 - - /* ignore IKEv2 packets - they will be handled by charon */ - if (pbs_room(&md->packet_pbs) > IKEV2_VERSION_OFFSET - && (md->packet_pbs.start[IKEV2_VERSION_OFFSET] & 0xF0) == IKEV2_VERSION) - { - DBG(DBG_CONTROLMORE, - DBG_log(" ignoring IKEv2 packet") - ) - return FALSE; - } - - return TRUE; -} - -/* process an input packet, possibly generating a reply. - * - * If all goes well, this routine eventually calls a state-specific - * transition function. - */ -static void -process_packet(struct msg_digest **mdp) -{ - struct msg_digest *md = *mdp; - const struct state_microcode *smc; - bool new_iv_set = FALSE; - bool restore_iv = FALSE; - u_char new_iv[MAX_DIGEST_LEN]; - u_int new_iv_len = 0; - - struct state *st = NULL; - enum state_kind from_state = STATE_UNDEFINED; /* state we started in */ - -#define SEND_NOTIFICATION(t) { \ - if (st) send_notification_from_state(st, from_state, t); \ - else send_notification_from_md(md, t); } - - if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs)) - { - /* Identify specific failures: - * - bad ISAKMP major/minor version numbers - */ - if (md->packet_pbs.roof - md->packet_pbs.cur >= (ptrdiff_t)isakmp_hdr_desc.size) - { - struct isakmp_hdr *hdr = (struct isakmp_hdr *)md->packet_pbs.cur; - if ((hdr->isa_version >> ISA_MAJ_SHIFT) != ISAKMP_MAJOR_VERSION) - { - SEND_NOTIFICATION(ISAKMP_INVALID_MAJOR_VERSION); - return; - } - else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION) - { - SEND_NOTIFICATION(ISAKMP_INVALID_MINOR_VERSION); - return; - } - } - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - if (md->packet_pbs.roof != md->message_pbs.roof) - { - plog("size (%u) differs from size specified in ISAKMP HDR (%u)" - , (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length); -#ifdef CISCO_QUIRKS - if (pbs_room(&md->packet_pbs) - md->hdr.isa_length == 16) - plog("Cisco VPN client appends 16 surplus NULL bytes"); - else -#endif - return; - } - - switch (md->hdr.isa_xchg) - { -#ifdef NOTYET - case ISAKMP_XCHG_NONE: - case ISAKMP_XCHG_BASE: -#endif - - case ISAKMP_XCHG_IDPROT: /* part of a Main Mode exchange */ - if (md->hdr.isa_msgid != MAINMODE_MSGID) - { - plog("Message ID was 0x%08lx but should be zero in Main Mode", - (unsigned long) md->hdr.isa_msgid); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("Initiator Cookie must not be zero in Main Mode message"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - /* initial message from initiator - * ??? what if this is a duplicate of another message? - */ - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - plog("initial Main Mode message is invalid:" - " its Encrypted Flag is on"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - - /* don't build a state until the message looks tasty */ - from_state = STATE_MAIN_R0; - } - else - { - /* not an initial message */ - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - /* perhaps this is a first message from the responder - * and contains a responder cookie that we've not yet seen. - */ - st = find_state(md->hdr.isa_icookie, zero_cookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - plog("Main Mode message is part of an unknown exchange"); - /* XXX Could send notification back */ - return; - } - } - set_cur_state(st); - from_state = st->st_state; - } - break; - -#ifdef NOTYET - case ISAKMP_XCHG_AO: - case ISAKMP_XCHG_AGGR: -#endif - - case ISAKMP_XCHG_INFO: /* an informational exchange */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, MAINMODE_MSGID); - - if (st != NULL) - set_cur_state(st); - - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - if (st == NULL) - { - plog("Informational Exchange is for an unknown (expired?) SA"); - /* XXX Could send notification back */ - return; - } - - if (!IS_ISAKMP_ENCRYPTED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "encrypted Informational Exchange message is invalid" - " because no key is known"); - /* XXX Could send notification back */ - return; - } - - if (md->hdr.isa_msgid == MAINMODE_MSGID) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because" - " it has a Message ID of 0"); - /* XXX Could send notification back */ - return; - } - - if (!reserve_msgid(st, md->hdr.isa_msgid)) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because" - " it has a previously used Message ID (0x%08lx)" - , (unsigned long)md->hdr.isa_msgid); - /* XXX Could send notification back */ - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len); - st->st_ph1_iv_len = st->st_new_iv_len; - - /* backup new_iv */ - new_iv_len = st->st_new_iv_len; - passert(new_iv_len <= MAX_DIGEST_LEN) - memcpy(new_iv, st->st_new_iv, new_iv_len); - restore_iv = TRUE; - } - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - from_state = STATE_INFO_PROTECTED; - } - else - { - if (st != NULL && IS_ISAKMP_ENCRYPTED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message" - " must be encrypted"); - /* XXX Could send notification back */ - return; - } - from_state = STATE_INFO; - } - break; - - case ISAKMP_XCHG_QUICK: /* part of a Quick Mode exchange */ - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("Quick Mode message is invalid because" - " it has an Initiator Cookie of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - plog("Quick Mode message is invalid because" - " it has a Responder Cookie of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (md->hdr.isa_msgid == MAINMODE_MSGID) - { - plog("Quick Mode message is invalid because" - " it has a Message ID of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - /* No appropriate Quick Mode state. - * See if we have a Main Mode state. - * ??? what if this is a duplicate of another message? - */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, MAINMODE_MSGID); - - if (st == NULL) - { - plog("Quick Mode message is for a non-existent (expired?)" - " ISAKMP SA"); - /* XXX Could send notification back */ - return; - } - - set_cur_state(st); - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because" - " it is for an incomplete ISAKMP SA"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED /* XXX ? */); - return; - } - - /* only accept this new Quick Mode exchange if it has a unique message ID */ - if (!reserve_msgid(st, md->hdr.isa_msgid)) - { - loglog(RC_LOG_SERIOUS, "Quick Mode I1 message is unacceptable because" - " it uses a previously used Message ID 0x%08lx" - " (perhaps this is a duplicated packet)" - , (unsigned long) md->hdr.isa_msgid); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - /* Quick Mode Initial IV */ - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - from_state = STATE_QUICK_R0; - } - else - { - set_cur_state(st); - from_state = st->st_state; - } - - break; - - case ISAKMP_XCHG_MODE_CFG: - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("ModeCfg message is invalid because" - " it has an Initiator Cookie of 0"); - /* XXX Could send notification back */ - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - plog("ModeCfg message is invalid because" - " it has a Responder Cookie of 0"); - /* XXX Could send notification back */ - return; - } - - if (md->hdr.isa_msgid == 0) - { - plog("ModeCfg message is invalid because" - " it has a Message ID of 0"); - /* XXX Could send notification back */ - return; - } - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - bool has_xauth_policy; - - /* No appropriate ModeCfg state. - * See if we have a Main Mode state. - * ??? what if this is a duplicate of another message? - */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, 0); - - if (st == NULL) - { - plog("ModeCfg message is for a non-existent (expired?)" - " ISAKMP SA"); - /* XXX Could send notification back */ - return; - } - - set_cur_state(st); - - /* the XAUTH_STATUS message might have a new msgid */ - if (st->st_state == STATE_XAUTH_I1) - { - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - from_state = st->st_state; - break; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "ModeCfg message is unacceptable because" - " it is for an incomplete ISAKMP SA (state=%s)" - , enum_name(&state_names, st->st_state)); - /* XXX Could send notification back */ - return; - } - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - /* - * okay, now we have to figure out if we are receiving a bogus - * new message in an outstanding XAUTH server conversation - * (i.e. a reply to our challenge) - * (this occurs with some broken other implementations). - * - * or if receiving for the first time, an XAUTH challenge. - * - * or if we are getting a MODECFG request. - * - * we distinguish these states because we can not both be an - * XAUTH server and client, and our policy tells us which - * one we are. - * - * to complicate further, it is normal to start a new msgid - * when going from one state to another, or when restarting - * the challenge. - * - */ - - has_xauth_policy = (st->st_connection->policy - & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK)) - != LEMPTY; - - if (has_xauth_policy && !st->st_xauth.started - && IS_PHASE1(st->st_state)) - { - from_state = STATE_XAUTH_I0; - } - else if (st->st_connection->spd.that.modecfg - && IS_PHASE1(st->st_state)) - { - from_state = STATE_MODE_CFG_R0; - } - else if (st->st_connection->spd.this.modecfg - && IS_PHASE1(st->st_state)) - { - from_state = STATE_MODE_CFG_I0; - } - else - { - /* XXX check if we are being a mode config server here */ - plog("received ModeCfg message when in state %s, and we aren't mode config client" - , enum_name(&state_names, st->st_state)); - return; - } - } - else - { - set_cur_state(st); - from_state = st->st_state; - } - break; - -#ifdef NOTYET - case ISAKMP_XCHG_NGRP: - case ISAKMP_XCHG_ACK_INFO: -#endif - - default: - plog("unsupported exchange type %s in message" - , enum_show(&exchange_names, md->hdr.isa_xchg)); - SEND_NOTIFICATION(ISAKMP_UNSUPPORTED_EXCHANGE_TYPE); - return; - } - - /* We have found a from_state, and perhaps a state object. - * If we need to build a new state object, - * we wait until the packet has been sanity checked. - */ - - /* We don't support the Commit Flag. It is such a bad feature. - * It isn't protected -- neither encrypted nor authenticated. - * A man in the middle turns it on, leading to DoS. - * We just ignore it, with a warning. - * By placing the check here, we could easily add a policy bit - * to a connection to suppress the warning. This might be useful - * because the Commit Flag is expected from some peers. - */ - if (md->hdr.isa_flags & ISAKMP_FLAG_COMMIT) - { - plog("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag"); - } - - /* Set smc to describe this state's properties. - * Look up the appropriate microcode based on state and - * possibly Oakley Auth type. - */ - passert(STATE_IKE_FLOOR <= from_state && from_state < STATE_IKE_ROOF); - smc = ike_microcode_index[from_state - STATE_IKE_FLOOR]; - - if (st != NULL) - { - u_int16_t auth; - - switch (st->st_oakley.auth) - { - case XAUTHInitPreShared: - case XAUTHRespPreShared: - auth = OAKLEY_PRESHARED_KEY; - break; - case XAUTHInitRSA: - case XAUTHRespRSA: - auth = OAKLEY_RSA_SIG; - break; - default: - auth = st->st_oakley.auth; - } - - while (!LHAS(smc->flags, auth)) - { - smc++; - passert(smc->state == from_state); - } - } - - /* Ignore a packet if the state has a suspended state transition - * Probably a duplicated packet but the original packet is not yet - * recorded in st->st_rpacket, so duplicate checking won't catch. - * ??? Should the packet be recorded earlier to improve diagnosis? - */ - if (st != NULL && st->st_suspended_md != NULL) - { - loglog(RC_LOG, "discarding packet received during DNS lookup in %s" - , enum_name(&state_names, st->st_state)); - return; - } - - /* Detect and handle duplicated packets. - * This won't work for the initial packet of an exchange - * because we won't have a state object to remember it. - * If we are in a non-receiving state (terminal), and the preceding - * state did transmit, then the duplicate may indicate that that - * transmission wasn't received -- retransmit it. - * Otherwise, just discard it. - * ??? Notification packets are like exchanges -- I hope that - * they are idempotent! - */ - if (st != NULL - && st->st_rpacket.ptr != NULL - && st->st_rpacket.len == pbs_room(&md->packet_pbs) - && memeq(st->st_rpacket.ptr, md->packet_pbs.start, st->st_rpacket.len)) - { - if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE) - { - if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS) - { - st->st_retransmit++; - loglog(RC_RETRANSMISSION - , "retransmitting in response to duplicate packet; already %s" - , enum_name(&state_names, st->st_state)); - send_packet(st, "retransmit in response to duplicate"); - } - else - { - loglog(RC_LOG_SERIOUS, "discarding duplicate packet -- exhausted retransmission; already %s" - , enum_name(&state_names, st->st_state)); - } - } - else - { - loglog(RC_LOG_SERIOUS, "discarding duplicate packet; already %s" - , enum_name(&state_names, st->st_state)); - } - return; - } - - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - DBG(DBG_CRYPT, DBG_log("received encrypted packet from %s:%u" - , ip_str(&md->sender), (unsigned)md->sender_port)); - - if (st == NULL) - { - plog("discarding encrypted message for an unknown ISAKMP SA"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED /* XXX ? */); - return; - } - if (st->st_skeyid_e.ptr == (u_char *) NULL) - { - loglog(RC_LOG_SERIOUS, "discarding encrypted message" - " because we haven't yet negotiated keying materiel"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - - /* Mark as encrypted */ - md->encrypted = TRUE; - - DBG(DBG_CRYPT, DBG_log("decrypting %u bytes using algorithm %s" - , (unsigned) pbs_left(&md->message_pbs) - , enum_show(&oakley_enc_names, st->st_oakley.encrypt))); - - /* do the specified decryption - * - * IV is from st->st_iv or (if new_iv_set) st->st_new_iv. - * The new IV is placed in st->st_new_iv - * - * See RFC 2409 "IKE" Appendix B - * - * XXX The IV should only be updated really if the packet - * is successfully processed. - * We should keep this value, check for a success return - * value from the parsing routines and then replace. - * - * Each post phase 1 exchange generates IVs from - * the last phase 1 block, not the last block sent. - */ - { - size_t crypter_block_size, crypter_iv_size; - encryption_algorithm_t enc_alg; - crypter_t *crypter; - chunk_t data, iv; - char *new_iv; - - enc_alg = oakley_to_encryption_algorithm(st->st_oakley.encrypt); - crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, st->st_enc_key.len); - crypter_block_size = crypter->get_block_size(crypter); - crypter_iv_size = crypter->get_iv_size(crypter); - - if (pbs_left(&md->message_pbs) % crypter_block_size != 0) - { - loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - /* XXX Detect weak keys */ - - /* grab a copy of raw packet (for duplicate packet detection) */ - md->raw_packet = chunk_create(md->packet_pbs.start, pbs_room(&md->packet_pbs)); - md->raw_packet = chunk_clone(md->raw_packet); - - data = chunk_create(md->message_pbs.cur, pbs_left(&md->message_pbs)); - - /* Decrypt everything after header */ - if (!new_iv_set) - { - /* use old IV */ - passert(st->st_iv_len <= sizeof(st->st_new_iv)); - st->st_new_iv_len = st->st_iv_len; - memcpy(st->st_new_iv, st->st_iv, st->st_new_iv_len); - } - - /* form iv by truncation */ - st->st_new_iv_len = crypter_iv_size; - iv = chunk_create(st->st_new_iv, st->st_new_iv_len); - new_iv = alloca(crypter_iv_size); - memcpy(new_iv, data.ptr + data.len - crypter_iv_size, - crypter_iv_size); - - crypter->set_key(crypter, st->st_enc_key); - crypter->decrypt(crypter, data, iv, NULL); - crypter->destroy(crypter); - - memcpy(st->st_new_iv, new_iv, crypter_iv_size); - if (restore_iv) - { - memcpy(st->st_new_iv, new_iv, new_iv_len); - st->st_new_iv_len = new_iv_len; - } - } - - DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur - , md->message_pbs.roof - md->message_pbs.cur); - - DBG_cond_dump(DBG_CRYPT, "next IV:" - , st->st_new_iv, st->st_new_iv_len); - } - else - { - /* packet was not encryped -- should it have been? */ - - if (smc->flags & SMF_INPUT_ENCRYPTED) - { - loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - } - - /* Digest the message. - * Padding must be removed to make hashing work. - * Padding comes from encryption (so this code must be after decryption). - * Padding rules are described before the definition of - * struct isakmp_hdr in packet.h. - */ - { - struct payload_digest *pd = md->digest; - int np = md->hdr.isa_np; - lset_t needed = smc->req_payloads; - const char *excuse - = LIN(SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT, smc->flags) - ? "probable authentication failure (mismatch of preshared secrets?): " - : ""; - - while (np != ISAKMP_NEXT_NONE) - { - struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL; - - if (pd == &md->digest[PAYLIMIT]) - { - loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - switch (np) - { - case ISAKMP_NEXT_NATD_RFC: - case ISAKMP_NEXT_NATOA_RFC: - if (!st || !(st->nat_traversal & NAT_T_WITH_RFC_VALUES)) - { - /* - * don't accept NAT-D/NAT-OA reloc directly in message, unless - * we're using NAT-T RFC - */ - sd = NULL; - } - break; - } - - if (sd == NULL) - { - /* payload type is out of range or requires special handling */ - switch (np) - { - case ISAKMP_NEXT_ID: - sd = IS_PHASE1(from_state) - ? &isakmp_identification_desc : &isakmp_ipsec_identification_desc; - break; - case ISAKMP_NEXT_NATD_DRAFTS: - np = ISAKMP_NEXT_NATD_RFC; /* NAT-D relocated */ - sd = payload_descs[np]; - break; - case ISAKMP_NEXT_NATOA_DRAFTS: - np = ISAKMP_NEXT_NATOA_RFC; /* NAT-OA relocated */ - sd = payload_descs[np]; - break; - default: - loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or" - " unexpected payload type (%s) at the outermost level" - , excuse, enum_show(&payload_names, np)); - SEND_NOTIFICATION(ISAKMP_INVALID_PAYLOAD_TYPE); - return; - } - } - - { - lset_t s = LELEM(np); - - if (LDISJOINT(s - , needed | smc->opt_payloads| LELEM(ISAKMP_NEXT_N) | LELEM(ISAKMP_NEXT_D))) - { - loglog(RC_LOG_SERIOUS, "%smessage ignored because it " - "contains an unexpected payload type (%s)" - , excuse, enum_show(&payload_names, np)); - SEND_NOTIFICATION(ISAKMP_INVALID_PAYLOAD_TYPE); - return; - } - needed &= ~s; - } - - if (!in_struct(&pd->payload, sd, &md->message_pbs, &pd->pbs)) - { - loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse); - if (md->hdr.isa_xchg != ISAKMP_XCHG_INFO) - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - /* place this payload at the end of the chain for this type */ - { - struct payload_digest **p; - - for (p = &md->chain[np]; *p != NULL; p = &(*p)->next) - ; - *p = pd; - pd->next = NULL; - } - - np = pd->payload.generic.isag_np; - pd++; - - /* since we've digested one payload happily, it is probably - * the case that any decryption worked. So we will not suggest - * encryption failure as an excuse for subsequent payload - * problems. - */ - excuse = ""; - } - - md->digest_roof = pd; - - DBG(DBG_PARSING, - if (pbs_left(&md->message_pbs) != 0) - DBG_log("removing %d bytes of padding", (int) pbs_left(&md->message_pbs))); - - md->message_pbs.roof = md->message_pbs.cur; - - /* check that all mandatory payloads appeared */ - - if (needed != 0) - { - loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s" - , enum_show(&state_names, from_state) - , bitnamesof(payload_name, needed)); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - - /* more sanity checking: enforce most ordering constraints */ - - if (IS_PHASE1(from_state)) - { - /* rfc2409: The Internet Key Exchange (IKE), 5 Exchanges: - * "The SA payload MUST precede all other payloads in a phase 1 exchange." - */ - if (md->chain[ISAKMP_NEXT_SA] != NULL - && md->hdr.isa_np != ISAKMP_NEXT_SA) - { - loglog(RC_LOG_SERIOUS, "malformed Phase 1 message: does not start with an SA payload"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - else if (IS_QUICK(from_state)) - { - /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode - * - * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP - * header and a SA payload MUST immediately follow the HASH." - * [NOTE: there may be more than one SA payload, so this is not - * totally reasonable. Probably all SAs should be so constrained.] - * - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - * - * "With the exception of the HASH, SA, and the optional ID payloads, - * there are no payload ordering restrictions on Quick Mode." - */ - - if (md->hdr.isa_np != ISAKMP_NEXT_HASH) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: does not start with a HASH payload"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - { - struct payload_digest *p; - int i; - - for (p = md->chain[ISAKMP_NEXT_SA], i = 1; p != NULL - ; p = p->next, i++) - { - if (p != &md->digest[i]) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: SA payload is in wrong position"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - } - - /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode: - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - */ - { - struct payload_digest *id = md->chain[ISAKMP_NEXT_ID]; - - if (id != NULL) - { - if (id->next == NULL || id->next->next != NULL) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" - " if any ID payload is present," - " there must be exactly two"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - if (id+1 != id->next) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" - " the ID payloads are not adjacent"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - } - } - - /* Ignore payloads that we don't handle: - * Delete, Notification, VendorID - */ - /* XXX Handle deletions */ - /* XXX Handle Notifications */ - /* XXX Handle VID payloads */ - { - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_N]; p != NULL; p = p->next) - { - if (p->payload.notification.isan_type != R_U_THERE - && p->payload.notification.isan_type != R_U_THERE_ACK) - { - loglog(RC_LOG_SERIOUS, "ignoring informational payload, type %s" - , enum_show(¬ification_names, p->payload.notification.isan_type)); - } - DBG_cond_dump(DBG_PARSING, "info:", p->pbs.cur, pbs_left(&p->pbs)); - } - - for (p = md->chain[ISAKMP_NEXT_D]; p != NULL; p = p->next) - { - accept_delete(st, md, p); - DBG_cond_dump(DBG_PARSING, "del:", p->pbs.cur, pbs_left(&p->pbs)); - } - - for (p = md->chain[ISAKMP_NEXT_VID]; p != NULL; p = p->next) - { - handle_vendorid(md, p->pbs.cur, pbs_left(&p->pbs)); - } - } - md->from_state = from_state; - md->smc = smc; - md->st = st; - - /* possibly fill in hdr */ - if (smc->first_out_payload != ISAKMP_NEXT_NONE) - echo_hdr(md, (smc->flags & SMF_OUTPUT_ENCRYPTED) != 0 - , smc->first_out_payload); - - complete_state_transition(mdp, smc->processor(md)); -} - -/* complete job started by the state-specific state transition function */ - -void -complete_state_transition(struct msg_digest **mdp, stf_status result) -{ - bool has_xauth_policy; - bool is_xauth_server; - struct msg_digest *md = *mdp; - const struct state_microcode *smc = md->smc; - enum state_kind from_state = md->from_state; - struct state *st; - - cur_state = st = md->st; /* might have changed */ - - /* If state has DPD support, import it */ - if (st && md->dpd) - st->st_dpd = TRUE; - - switch (result) - { - case STF_IGNORE: - break; - - case STF_SUSPEND: - /* the stf didn't complete its job: don't relase md */ - *mdp = NULL; - break; - - case STF_OK: - /* advance the state */ - st->st_state = smc->next_state; - - /* Delete previous retransmission event. - * New event will be scheduled below. - */ - delete_event(st); - - /* replace previous receive packet with latest */ - - free(st->st_rpacket.ptr); - - if (md->encrypted) - { - /* if encrypted, duplication already done */ - st->st_rpacket = md->raw_packet; - md->raw_packet.ptr = NULL; - } - else - { - st->st_rpacket = chunk_create(md->packet_pbs.start, - pbs_room(&md->packet_pbs)); - st->st_rpacket = chunk_clone(st->st_rpacket); - } - - /* free previous transmit packet */ - chunk_free(&st->st_tpacket); - - /* if requested, send the new reply packet */ - if (smc->flags & SMF_REPLY) - { - close_output_pbs(&md->reply); /* good form, but actually a no-op */ - - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - if (nat_traversal_enabled) - nat_traversal_change_port_lookup(md, md->st); - - /* actually send the packet - * Note: this is a great place to implement "impairments" - * for testing purposes. Suppress or duplicate the - * send_packet call depending on st->st_state. - */ - send_packet(st, enum_name(&state_names, from_state)); - } - - /* Schedule for whatever timeout is specified */ - { - time_t delay = UNDEFINED_TIME; - enum event_type kind = smc->timeout_event; - bool agreed_time = FALSE; - connection_t *c = st->st_connection; - - switch (kind) - { - case EVENT_RETRANSMIT: /* Retransmit packet */ - delay = EVENT_RETRANSMIT_DELAY_0; - break; - - case EVENT_SA_REPLACE: /* SA replacement event */ - if (IS_PHASE1(st->st_state)) - { - /* Note: we will defer to the "negotiated" (dictated) - * lifetime if we are POLICY_DONT_REKEY. - * This allows the other side to dictate - * a time we would not otherwise accept - * but it prevents us from having to initiate - * rekeying. The negative consequences seem - * minor. - */ - delay = c->sa_ike_life_seconds; - if ((c->policy & POLICY_DONT_REKEY) - || delay >= st->st_oakley.life_seconds) - { - agreed_time = TRUE; - delay = st->st_oakley.life_seconds; - } - } - else - { - /* Delay is min of up to four things: - * each can limit the lifetime. - */ - delay = c->sa_ipsec_life_seconds; - if (st->st_ah.present - && delay >= st->st_ah.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_ah.attrs.life_seconds; - } - if (st->st_esp.present - && delay >= st->st_esp.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_esp.attrs.life_seconds; - } - if (st->st_ipcomp.present - && delay >= st->st_ipcomp.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_ipcomp.attrs.life_seconds; - } - } - - /* By default, we plan to rekey. - * - * If there isn't enough time to rekey, plan to - * expire. - * - * If we are --dontrekey, a lot more rules apply. - * If we are the Initiator, use REPLACE_IF_USED. - * If we are the Responder, and the dictated time - * was unacceptable (too large), plan to REPLACE - * (the only way to ratchet down the time). - * If we are the Responder, and the dictated time - * is acceptable, plan to EXPIRE. - * - * Important policy lies buried here. - * For example, we favour the initiator over the - * responder by making the initiator start rekeying - * sooner. Also, fuzz is only added to the - * initiator's margin. - * - * Note: for ISAKMP SA, we let the negotiated - * time stand (implemented by earlier logic). - */ - if (agreed_time - && (c->policy & POLICY_DONT_REKEY)) - { - kind = (smc->flags & SMF_INITIATOR) - ? EVENT_SA_REPLACE_IF_USED - : EVENT_SA_EXPIRE; - } - if (kind != EVENT_SA_EXPIRE) - { - unsigned long marg = c->sa_rekey_margin; - - if (smc->flags & SMF_INITIATOR) - marg += marg - * c->sa_rekey_fuzz / 100.E0 - * (rand() / (RAND_MAX + 1.E0)); - else - marg /= 2; - - if ((unsigned long)delay > marg) - { - delay -= marg; - st->st_margin = marg; - } - else - { - kind = EVENT_SA_EXPIRE; - } - } - break; - - case EVENT_NULL: /* non-event */ - case EVENT_REINIT_SECRET: /* Refresh cookie secret */ - default: - bad_case(kind); - } - event_schedule(kind, delay, st); - } - - /* tell whack and log of progress */ - { - const char *story = state_story[st->st_state]; - enum rc_type w = RC_NEW_STATE + st->st_state; - char sadetails[128]; - - sadetails[0]='\0'; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - char *b = sadetails; - const char *ini = " {"; - const char *fin = ""; - - /* -1 is to leave space for "fin" */ - - if (st->st_esp.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sESP=>0x%08x <0x%08x" - , ini - , ntohl(st->st_esp.attrs.spi) - , ntohl(st->st_esp.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_ah.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sAH=>0x%08x <0x%08x" - , ini - , ntohl(st->st_ah.attrs.spi) - , ntohl(st->st_ah.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_ipcomp.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sIPCOMP=>0x%08x <0x%08x" - , ini - , ntohl(st->st_ipcomp.attrs.spi) - , ntohl(st->st_ipcomp.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->nat_traversal) - { - char oa[ADDRTOT_BUF]; - addrtot(&st->nat_oa, 0, oa, sizeof(oa)); - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sNATOA=%s" - , ini, oa); - ini = " "; - fin = "}"; - } - - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_dpd) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sDPD" - , ini); - ini = " "; - fin = "}"; - } - - strcat(b, fin); - } - - if (IS_ISAKMP_SA_ESTABLISHED(st->st_state) - || IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - /* log our success */ - plog("%s%s", story, sadetails); - w = RC_SUCCESS; - } - - /* tell whack our progress */ - whack_log(w - , "%s: %s%s" - , enum_name(&state_names, st->st_state) - , story, sadetails); - } - - has_xauth_policy = (st->st_connection->policy - & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK)) - != LEMPTY; - is_xauth_server = (st->st_connection->policy - & POLICY_XAUTH_SERVER) - != LEMPTY; - - /* Should we start XAUTH as a server */ - if (has_xauth_policy && is_xauth_server - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_xauth.started) - { - DBG(DBG_CONTROL, - DBG_log("starting XAUTH server") - ) - xauth_send_request(st); - break; - } - - /* Wait for XAUTH request from server */ - if (has_xauth_policy && !is_xauth_server - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_xauth.started) - { - DBG(DBG_CONTROL, - DBG_log("waiting for XAUTH request from server") - ) - break; - } - - /* Should we start ModeConfig as a client? */ - if (st->st_connection->spd.this.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !(st->st_connection->policy & POLICY_MODECFG_PUSH) - && !st->st_modecfg.started) - { - DBG(DBG_CONTROL, - DBG_log("starting ModeCfg client in pull mode") - ) - modecfg_send_request(st); - break; - } - - /* Should we start ModeConfig as a server? */ - if (st->st_connection->spd.that.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_modecfg.started - && (st->st_connection->policy & POLICY_MODECFG_PUSH)) - { - DBG(DBG_CONTROL, - DBG_log("starting ModeCfg server in push mode") - ) - modecfg_send_set(st); - break; - } - - /* Wait for ModeConfig set from server */ - if (st->st_connection->spd.this.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_modecfg.vars_set) - { - DBG(DBG_CONTROL, - DBG_log("waiting for ModeCfg set from server") - ) - break; - } - - if (smc->flags & SMF_RELEASE_PENDING_P2) - { - /* Initiate any Quick Mode negotiations that - * were waiting to piggyback on this Keying Channel. - * - * ??? there is a potential race condition - * if we are the responder: the initial Phase 2 - * message might outrun the final Phase 1 message. - * I think that retransmission will recover. - */ - unpend(st); - } - - if (IS_ISAKMP_SA_ESTABLISHED(st->st_state) - || IS_IPSEC_SA_ESTABLISHED(st->st_state)) - release_whack(st); - break; - - case STF_INTERNAL_ERROR: - whack_log(RC_INTERNALERR + md->note - , "%s: internal error" - , enum_name(&state_names, st->st_state)); - - DBG(DBG_CONTROL, - DBG_log("state transition function for %s had internal error" - , enum_name(&state_names, from_state))); - break; - - default: /* a shortcut to STF_FAIL, setting md->note */ - passert(result > STF_FAIL); - md->note = result - STF_FAIL; - result = STF_FAIL; - /* FALL THROUGH ... */ - case STF_FAIL: - /* As it is, we act as if this message never happened: - * whatever retrying was in place, remains in place. - */ - whack_log(RC_NOTIFICATION + md->note - , "%s: %s" - , enum_name(&state_names, (st == NULL)? STATE_MAIN_R0:st->st_state) - , enum_name(¬ification_names, md->note)); - - SEND_NOTIFICATION(md->note); - - DBG(DBG_CONTROL, - DBG_log("state transition function for %s failed: %s" - , enum_name(&state_names, from_state) - , enum_name(¬ification_names, md->note))); - break; - } -} diff --git a/src/pluto/demux.h b/src/pluto/demux.h deleted file mode 100644 index 6ce53c14f..000000000 --- a/src/pluto/demux.h +++ /dev/null @@ -1,97 +0,0 @@ -/* demultiplex incoming IKE messages - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DEMUX_H -#define _DEMUX_H - -#include "packet.h" -#include "state.h" - -extern void init_demux(void); -extern bool send_packet(struct state *st, const char *where); -extern void comm_handle(const struct iface *ifp); - -extern u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE]; - -/* State transition function infrastructure - * - * com_handle parses a message, decides what state object it applies to, - * and calls the appropriate state transition function (STF). - * These declarations define the interface to these functions. - * - * Each STF must be able to be restarted up to any failure point: - * a later message will cause the state to be re-entered. This - * explains the use of the replace macro and the care in handling - * MP_INT members of struct state. - */ - -struct payload_digest { - pb_stream pbs; - union payload payload; - struct payload_digest *next; /* of same kind */ -}; - -/* message digest - * Note: raw_packet and packet_pbs are "owners" of space on heap. - */ - -struct msg_digest { - struct msg_digest *next; /* for free list */ - chunk_t raw_packet; /* if encrypted, received packet before decryption */ - const struct iface *iface; /* interface on which message arrived */ - ip_address sender; /* where message came from */ - u_int16_t sender_port; /* host order */ - pb_stream packet_pbs; /* whole packet */ - pb_stream message_pbs; /* message to be processed */ - struct isakmp_hdr hdr; /* message's header */ - bool encrypted; /* was it encrypted? */ - enum state_kind from_state; /* state we started in */ - const struct state_microcode *smc; /* microcode for initial state */ - struct state *st; /* current state object */ - pb_stream reply; /* room for reply */ - pb_stream rbody; /* room for reply body (after header) */ - notification_t note; /* reason for failure */ - bool dpd; /* peer supports RFC 3706 DPD */ - bool openpgp; /* peer supports OpenPGP certificates */ - bool ms_nt5; /* peer is a windows 2000+ host */ - -# define PAYLIMIT 40 - struct payload_digest - digest[PAYLIMIT], - *digest_roof, - *chain[ISAKMP_NEXT_ROOF]; - unsigned short nat_traversal_vid; -}; - -extern void release_md(struct msg_digest *md); - -/* status for state-transition-function - * Note: STF_FAIL + notification_t means fail with that notification - */ - -typedef enum { - STF_IGNORE, /* don't respond */ - STF_SUSPEND, /* unfinished -- don't release resources */ - STF_OK, /* success */ - STF_INTERNAL_ERROR, /* discard everything, we failed */ - STF_FAIL /* discard everything, something failed. notification_t added. */ -} stf_status; - -typedef stf_status state_transition_fn(struct msg_digest *md); - -extern void complete_state_transition(struct msg_digest **mdp, stf_status result); - -extern void free_md_pool(void); - -#endif /* _DEMUX_H */ diff --git a/src/pluto/dnskey.c b/src/pluto/dnskey.c deleted file mode 100644 index 91b1b6ac1..000000000 --- a/src/pluto/dnskey.c +++ /dev/null @@ -1,1590 +0,0 @@ -/* Find public key in DNS - * Copyright (C) 2000-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* ??? for h_errno */ -#include - -#include - -#include -#include - -#include "constants.h" -#include "adns.h" /* needs */ -#include "defs.h" -#include "log.h" -#include "myid.h" -#include "connections.h" -#include "keys.h" /* needs connections.h */ -#include "dnskey.h" -#include "packet.h" -#include "timer.h" - -/* somebody has to decide */ -#define MAX_TXT_RDATA ((MAX_KEY_BYTES * 8 / 6) + 40) /* somewhat arbitrary overkill */ - -/* ADNS stuff */ - -int adns_qfd = NULL_FD, /* file descriptor for sending queries to adns (O_NONBLOCK) */ - adns_afd = NULL_FD; /* file descriptor for receiving answers from adns */ -static pid_t adns_pid = 0; -const char *pluto_adns_option = NULL; /* path from --pluto_adns */ - -int adns_restart_count; -#define ADNS_RESTART_MAX 20 - -void -init_adns(void) -{ - const char *adns_path = pluto_adns_option; - static const char adns_name[] = "_pluto_adns"; - const char *helper_bin_dir = getenv("IPSEC_LIBDIR"); - char adns_path_space[4096]; /* plenty long? */ - int qfds[2]; - int afds[2]; - - /* find a pathname to the ADNS program */ - if (adns_path == NULL) - { - /* pathname was not specified as an option: build it. - * First, figure out the directory to be used. - */ - ssize_t n; - - if (helper_bin_dir != NULL) - { - n = strlen(helper_bin_dir); - if ((size_t)n <= sizeof(adns_path_space) - sizeof(adns_name)) - { - strcpy(adns_path_space, helper_bin_dir); - if (n > 0 && adns_path_space[n -1] != '/') - { - adns_path_space[n++] = '/'; - } - } - } - else - { - /* The program will be in the same directory as Pluto, - * so we use the sympolic link /proc/self/exe to - * tell us of the path prefix. - */ - n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space)); - - if (n < 0) - { - exit_log_errno((e - , "readlink(\"/proc/self/exe\") failed in init_adns()")); - } - } - - if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name)) - { - exit_log("path to %s is too long", adns_name); - } - - while (n > 0 && adns_path_space[n - 1] != '/') - { - n--; - } - strcpy(adns_path_space + n, adns_name); - adns_path = adns_path_space; - } - if (access(adns_path, X_OK) < 0) - { - exit_log_errno((e, "%s missing or not executable", adns_path)); - } - - if (pipe(qfds) != 0 || pipe(afds) != 0) - { - exit_log_errno((e, "pipe(2) failed in init_adns()")); - } - - adns_pid = fork(); - switch (adns_pid) - { - case -1: - exit_log_errno((e, "fork() failed in init_adns()")); - - case 0: - /* child */ - { - /* Make stdin and stdout our pipes. - * Take care to handle case where pipes already use these fds. - */ - if (afds[1] == 0) - { - afds[1] = dup(afds[1]); /* avoid being overwritten */ - } - if (qfds[0] != 0) - { - dup2(qfds[0], 0); - close(qfds[0]); - } - if (afds[1] != 1) - { - dup2(afds[1], 1); - close(qfds[1]); - } - if (afds[0] > 1) - { - close(afds[0]); - } - if (afds[1] > 1) - { - close(afds[1]); - } - DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL)); - - execlp(adns_path, adns_name, NULL); - exit_log_errno((e, "execlp of %s failed", adns_path)); - } - default: - /* parent */ - close(qfds[0]); - adns_qfd = qfds[1]; - adns_afd = afds[0]; - close(afds[1]); - fcntl(adns_qfd, F_SETFD, FD_CLOEXEC); - fcntl(adns_afd, F_SETFD, FD_CLOEXEC); - fcntl(adns_qfd, F_SETFL, O_NONBLOCK); - break; - } -} - -void -stop_adns(void) -{ - close_any(adns_qfd); - adns_qfd = NULL_FD; - close_any(adns_afd); - adns_afd = NULL_FD; - - if (adns_pid != 0) - { - int status; - pid_t p = waitpid(adns_pid, &status, 0); - - if (p == -1) - { - log_errno((e, "waitpid for ADNS process failed")); - } - else if (WIFEXITED(status)) - { - if (WEXITSTATUS(status) != 0) - { - plog("ADNS process exited with status %d" - , (int) WEXITSTATUS(status)); - } - } - else if (WIFSIGNALED(status)) - { - plog("ADNS process terminated by signal %d", (int)WTERMSIG(status)); - } - else - { - plog("wait for end of ADNS process returned odd status 0x%x\n" - , status); - } - } -} - - - -/* tricky macro to pass any hot potato */ -#define TRY(x) { err_t ugh = x; if (ugh != NULL) return ugh; } - - -/* Process TXT X-IPsec-Server record, accumulating relevant ones - * in cr->gateways_from_dns, a list sorted by "preference". - * - * Format of TXT record body: X-IPsec-Server ( nnn ) = iii kkk - * nnn is a 16-bit unsigned integer preference - * iii is @FQDN or dotted-decimal IPv4 address or colon-hex IPv6 address - * kkk is an optional RSA public signing key in base 64. - * - * NOTE: we've got to be very wary of anything we find -- bad guys - * might have prepared it. - */ - -#define our_TXT_attr_string "X-IPsec-Server" -static const char our_TXT_attr[] = our_TXT_attr_string; - -identification_t* decode_iii(u_char **pp) -{ - identification_t *gw_id; - u_char *p = *pp + strspn(*pp, " \t"); - u_char *e = p + strcspn(p, " \t"); - u_char under = *e; - - if (p == e) - { - return NULL; - } - *e = '\0'; - gw_id = identification_create_from_string(p); - *e = under; - *pp = e + strspn(e, " \t"); - - return gw_id; -} - -static err_t process_txt_rr_body(u_char *str, bool doit, - enum dns_auth_level dns_auth_level, - struct adns_continuation *const cr) -{ - identification_t *client_id = cr->id; /* subject of query */ - u_char *p = str; - unsigned long pref = 0; - struct gw_info gi; - - p += strspn(p, " \t"); /* ignore leading whitespace */ - - /* is this for us? */ - if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0) - { - return NULL; /* neither interesting nor bad */ - } - - p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */ - p += strspn(p, " \t"); /* ignore leading whitespace */ - - /* decode '(' nnn ')' */ - if (*p != '(') - { - return "X-IPsec-Server missing '('"; - } - - { - char *e; - - p++; - pref = strtoul(p, &e, 0); - if ((u_char *)e == p) - { - return "malformed X-IPsec-Server priority"; - } - p = e + strspn(e, " \t"); - - if (*p != ')') - { - return "X-IPsec-Server priority missing ')'"; - } - p++; - p += strspn(p, " \t"); - - if (pref > 0xFFFF) - { - return "X-IPsec-Server priority larger than 0xFFFF"; - } - } - - /* time for '=' */ - - if (*p != '=') - { - return "X-IPsec-Server priority missing '='"; - } - p++; - p += strspn(p, " \t"); - - /* Decode iii (Security Gateway ID). */ - zero(&gi); /* before first use */ - - gi.gw_id = decode_iii(&p); - if (gi.gw_id == NULL) - { - return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; - } - - if (!cr->sgw_specified) - { - /* we don't know the peer's ID (because we are initiating - * and we don't know who to initiate with. - * So we're looking for gateway specs with an IP address - */ - if (gi.gw_id->get_type(gi.gw_id) != ID_IPV4_ADDR && - gi.gw_id->get_type(gi.gw_id) != ID_IPV6_ADDR) - { - DBG(DBG_DNS, - DBG_log("TXT %s record for '%Y': security gateway '%Y';" - " ignored because gateway's IP is unspecified", - our_TXT_attr, client_id, gi.gw_id); - ) - return NULL; /* we cannot use this record, but it isn't wrong */ - } - } - else - { - /* We do know the peer's ID (because we are responding) - * So we're looking for gateway specs specifying this known ID. - */ - identification_t *peer_id = cr->sgw_id; - - if (!peer_id->equals(peer_id, gi.gw_id)) - { - DBG(DBG_DNS, - DBG_log("TXT %s record for '%Y': security gateway '%Y';" - " ignored -- looking to confirm '%Y' as gateway", - our_TXT_attr, client_id, gi.gw_id, peer_id); - ) - return NULL; /* we cannot use this record, but it isn't wrong */ - } - } - - if (doit) - { - /* really accept gateway */ - struct gw_info **gwip; /* gateway insertion point */ - - gi.client_id = client_id; /* will need to unshare_id_content */ - - /* decode optional kkk: base 64 encoding of key */ - - gi.gw_key_present = *p != '\0'; - if (gi.gw_key_present) - { - /* Decode base 64 encoding of key. - * Similar code is in process_lwdnsq_key. - */ - u_char buf[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */ - size_t sz; - err_t ugh; - chunk_t rfc3110_chunk; - public_key_t *key; - - ugh = ttodatav(p, 0, 64, buf, sizeof(buf), &sz, - diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh) - { - return builddiag("malformed key data: %s", ugh); - } - if (sz > sizeof(buf)) - { - return builddiag("key data larger than %lu bytes", - (unsigned long) sizeof(buf)); - } - rfc3110_chunk = chunk_create(buf, sz); - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_BLOB_DNSKEY, rfc3110_chunk, - BUILD_END); - if (key == NULL) - { - return builddiag("invalid key data"); - } - - /* now find a key entry to put it in */ - gi.key = public_key_from_rsa(key); - - unreference_key(&cr->last_info); - cr->last_info = reference_key(gi.key); - } - - /* we're home free! Allocate everything and add to gateways list. */ - gi.refcnt = 1; - gi.pref = pref; - gi.key->dns_auth_level = dns_auth_level; - gi.key->last_tried_time = gi.key->last_worked_time = NO_TIME; - - /* find insertion point */ - for (gwip = &cr->gateways_from_dns; *gwip != NULL && (*gwip)->pref < pref; gwip = &(*gwip)->next) - ; - - DBG(DBG_DNS, - { - chunk_t keyid; - public_key_t *key = gi.key->public_key; - - if (gi.gw_key_present && - key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &keyid)) - { - DBG_log("gateway for %s is %s with key %#B", - client_id, gi.gw_id, &keyid); - } - else - { - DBG_log("gateway for '%Y' is '%Y'; no key specified", - client_id, gi.gw_id); - } - }); - - gi.next = *gwip; - *gwip = clone_thing(gi); - (*gwip)->gw_id = (*gwip)->gw_id->clone((*gwip)->gw_id); - (*gwip)->client_id = (*gwip)->client_id->clone((*gwip)->client_id); - } - - return NULL; -} - -static const char * -rr_typename(int type) -{ - switch (type) - { - case T_TXT: - return "TXT"; - case T_KEY: - return "KEY"; - default: - return "???"; - } -} - - -/* structure of Query Reply (RFC 1035 4.1.1): - * - * +---------------------+ - * | Header | - * +---------------------+ - * | Question | the question for the name server - * +---------------------+ - * | Answer | RRs answering the question - * +---------------------+ - * | Authority | RRs pointing toward an authority - * +---------------------+ - * | Additional | RRs holding additional information - * +---------------------+ - */ - -/* Header section format (as modified by RFC 2535 6.1): - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ID | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QDCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ANCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | NSCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ARCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ -struct qr_header { - u_int16_t id; /* 16-bit identifier to match query */ - - u_int16_t stuff; /* packed crud: */ - -#define QRS_QR 0x8000 /* QR: on if this is a response */ - -#define QRS_OPCODE_SHIFT 11 /* OPCODE field */ -#define QRS_OPCODE_MASK 0xF -#define QRSO_QUERY 0 /* standard query */ -#define QRSO_IQUERY 1 /* inverse query */ -#define QRSO_STATUS 2 /* server status request query */ - -#define QRS_AA 0x0400 /* AA: on if Authoritative Answer */ -#define QRS_TC 0x0200 /* TC: on if truncation happened */ -#define QRS_RD 0x0100 /* RD: on if recursion desired */ -#define QRS_RA 0x0080 /* RA: on if recursion available */ -#define QRS_Z 0x0040 /* Z: reserved; must be zero */ -#define QRS_AD 0x0020 /* AD: on if authentic data (RFC 2535) */ -#define QRS_CD 0x0010 /* AD: on if checking disabled (RFC 2535) */ - -#define QRS_RCODE_SHIFT 0 /* RCODE field: response code */ -#define QRS_RCODE_MASK 0xF -#define QRSR_OK 0 - - - u_int16_t qdcount; /* number of entries in question section */ - u_int16_t ancount; /* number of resource records in answer section */ - u_int16_t nscount; /* number of name server resource records in authority section */ - u_int16_t arcount; /* number of resource records in additional records section */ -}; - -static field_desc qr_header_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "ID", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "stuff", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "QD Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Answer Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Authority Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Additional Count", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc qr_header_desc = { - "Query Response Header", - qr_header_fields, - sizeof(struct qr_header) -}; - -/* Messages for codes in RCODE (see RFC 1035 4.1.1) */ -static const err_t rcode_text[QRS_RCODE_MASK + 1] = { - NULL, /* not an error */ - "Format error - The name server was unable to interpret the query", - "Server failure - The name server was unable to process this query" - " due to a problem with the name server", - "Name Error - Meaningful only for responses from an authoritative name" - " server, this code signifies that the domain name referenced in" - " the query does not exist", - "Not Implemented - The name server does not support the requested" - " kind of query", - "Refused - The name server refuses to perform the specified operation" - " for policy reasons", - /* the rest are reserved for future use */ - }; - -/* throw away a possibly compressed domain name */ - -static err_t -eat_name(pb_stream *pbs) -{ - u_char name_buf[NS_MAXDNAME + 2]; - u_char *ip = pbs->cur; - unsigned oi = 0; - unsigned jump_count = 0; - - for (;;) - { - u_int8_t b; - - if (ip >= pbs->roof) - return "ran out of message while skipping domain name"; - - b = *ip++; - if (jump_count == 0) - pbs->cur = ip; - - if (b == 0) - break; - - switch (b & 0xC0) - { - case 0x00: - /* we grab the next b characters */ - if (oi + b > NS_MAXDNAME) - return "domain name too long"; - - if (pbs->roof - ip <= b) - return "domain name falls off end of message"; - - if (oi != 0) - name_buf[oi++] = '.'; - - memcpy(name_buf + oi, ip, b); - oi += b; - ip += b; - if (jump_count == 0) - pbs->cur = ip; - break; - - case 0xC0: - { - unsigned ix; - - if (ip >= pbs->roof) - return "ran out of message in middle of compressed domain name"; - - ix = ((b & ~0xC0u) << 8) | *ip++; - if (jump_count == 0) - pbs->cur = ip; - - if (ix >= pbs_room(pbs)) - return "impossible compressed domain name"; - - /* Avoid infinite loop. - * There can be no more jumps than there are bytes - * in the packet. Not a tight limit, but good enough. - */ - jump_count++; - if (jump_count > pbs_room(pbs)) - return "loop in compressed domain name"; - - ip = pbs->start + ix; - } - break; - - default: - return "invalid code in label"; - } - } - - name_buf[oi++] = '\0'; - - DBG(DBG_DNS, DBG_log("skipping name %s", name_buf)); - - return NULL; -} - -static err_t -eat_name_helpfully(pb_stream *pbs, const char *context) -{ - err_t ugh = eat_name(pbs); - - return ugh == NULL? ugh - : builddiag("malformed name within DNS record of %s: %s", context, ugh); -} - -/* non-variable part of 4.1.2 Question Section entry: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / QNAME / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QTYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QCLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - -struct qs_fixed { - u_int16_t qtype; - u_int16_t qclass; -}; - -static field_desc qs_fixed_fields[] = { - { ft_loose_enum, 16/BITS_PER_BYTE, "QTYPE", &rr_qtype_names }, - { ft_loose_enum, 16/BITS_PER_BYTE, "QCLASS", &rr_class_names }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc qs_fixed_desc = { - "Question Section entry fixed part", - qs_fixed_fields, - sizeof(struct qs_fixed) -}; - -/* 4.1.3. Resource record format: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / / - * / NAME / - * | | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | TYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | CLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | TTL | - * | | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | RDLENGTH | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - * / RDATA / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - -struct rr_fixed { - u_int16_t type; - u_int16_t class; - u_int32_t ttl; /* actually signed */ - u_int16_t rdlength; -}; - - -static field_desc rr_fixed_fields[] = { - { ft_loose_enum, 16/BITS_PER_BYTE, "type", &rr_type_names }, - { ft_loose_enum, 16/BITS_PER_BYTE, "class", &rr_class_names }, - { ft_nat, 32/BITS_PER_BYTE, "TTL", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "RD length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc rr_fixed_desc = { - "Resource Record fixed part", - rr_fixed_fields, - /* note: following is tricky: avoids padding problems */ - offsetof(struct rr_fixed, rdlength) + sizeof(u_int16_t) -}; - -/* RFC 1035 3.3.14: TXT RRs have text in the RDATA field. - * It is in the form of a sequence of s as described in 3.3. - * unpack_txt_rdata() deals with this peculiar representation. - */ - -/* RFC 2535 3.1 KEY RDATA format: - * - * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | flags | protocol | algorithm | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | / - * / public key / - * / / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| - */ - -struct key_rdata { - u_int16_t flags; - u_int8_t protocol; - u_int8_t algorithm; -}; - -static field_desc key_rdata_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "flags", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "protocol", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc key_rdata_desc = { - "KEY RR RData fixed part", - key_rdata_fields, - sizeof(struct key_rdata) -}; - -/* RFC 2535 4.1 SIG RDATA format: - * - * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | type covered | algorithm | labels | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | original TTL | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | signature expiration | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | signature inception | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | key tag | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ signer's name + - * | / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-/ - * / / - * / signature / - * / / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -struct sig_rdata { - u_int16_t type_covered; - u_int8_t algorithm; - u_int8_t labels; - u_int32_t original_ttl; - u_int32_t sig_expiration; - u_int32_t sig_inception; - u_int16_t key_tag; -}; - -static field_desc sig_rdata_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "type_covered", NULL}, - { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL}, - { ft_nat, 8/BITS_PER_BYTE, "labels", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "original ttl", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "sig expiration", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "sig inception", NULL}, - { ft_nat, 16/BITS_PER_BYTE, "key tag", NULL}, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc sig_rdata_desc = { - "SIG RR RData fixed part", - sig_rdata_fields, - sizeof(struct sig_rdata) -}; - -/* handle a KEY Resource Record. */ - -#ifdef USE_KEYRR -static err_t -process_key_rr(u_char *ptr, size_t len -, bool doit /* should we capture information? */ -, enum dns_auth_level dns_auth_level -, struct adns_continuation *const cr) -{ - pb_stream pbs; - struct key_rdata kr; - - if (len < sizeof(struct key_rdata)) - return "KEY Resource Record's RD Length is too small"; - - init_pbs(&pbs, ptr, len, "KEY RR"); - - if (!in_struct(&kr, &key_rdata_desc, &pbs, NULL)) - return "failed to get fixed part of KEY Resource Record RDATA"; - - if (kr.protocol == 4 /* IPSEC (RFC 2535 3.1.3) */ - && kr.algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */ - && (kr.flags & 0x8000) == 0 /* use for authentication (3.1.2) */ - && (kr.flags & 0x2CF0) == 0) /* must be zero */ - { - /* we have what seems to be a tasty key */ - - if (doit) - { - chunk_t k = { pbs.cur, pbs_left(&pbs) }; - - TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &k - , &cr->keys_from_dns)); - } - } - return NULL; -} -#endif /* USE_KEYRR */ - - -/* unpack TXT rr RDATA into C string. - * A sequence of s as described in RFC 1035 3.3. - * We concatenate them. - */ -static err_t -unpack_txt_rdata(u_char *d, size_t dlen, const u_char *s, size_t slen) -{ - size_t i = 0 - , o = 0; - - while (i < slen) - { - size_t cl = s[i++]; - - if (i + cl > slen) - return "TXT rr RDATA representation malformed"; - - if (o + cl >= dlen) - return "TXT rr RDATA too large"; - - memcpy(d + o, s + i, cl); - i += cl; - o += cl; - } - d[o] = '\0'; - if (strlen(d) != o) - return "TXT rr RDATA contains a NUL"; - - return NULL; -} - -static err_t -process_txt_rr(u_char *rdata, size_t rdlen -, bool doit /* should we capture information? */ -, enum dns_auth_level dns_auth_level -, struct adns_continuation *const cr) -{ - u_char str[RSA_MAX_ENCODING_BYTES * 8 / 6 + 20]; /* space for unpacked RDATA */ - - TRY(unpack_txt_rdata(str, sizeof(str), rdata, rdlen)); - return process_txt_rr_body(str, doit, dns_auth_level, cr); -} - -static err_t -process_answer_section(pb_stream *pbs -, bool doit /* should we capture information? */ -, enum dns_auth_level *dns_auth_level -, u_int16_t ancount /* number of RRs in the answer section */ -, struct adns_continuation *const cr) -{ - const int type = cr->query.type; /* type of RR of interest */ - unsigned c; - - DBG(DBG_DNS, DBG_log("*Answer Section:")); - - for (c = 0; c != ancount; c++) - { - struct rr_fixed rrf; - size_t tail; - - /* ??? do we need to match the name? */ - - TRY(eat_name_helpfully(pbs, "Answer Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, pbs, NULL)) - return "failed to get fixed part of Answer Section Resource Record"; - - if (rrf.rdlength > pbs_left(pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - if (rrf.type == type && rrf.class == C_IN) - { - err_t ugh = NULL; - - switch (type) - { -#ifdef USE_KEYRR - case T_KEY: - ugh = process_key_rr(pbs->cur, tail, doit, *dns_auth_level, cr); - break; -#endif /* USE_KEYRR */ - case T_TXT: - ugh = process_txt_rr(pbs->cur, tail, doit, *dns_auth_level, cr); - break; - case T_SIG: - /* Check if SIG RR authenticates what we are learning. - * The RRset covered by a SIG must have the same owner, - * class, and type. - * For us, the class is always C_IN, so that matches. - * We decode the SIG RR's fixed part to check - * that the type_covered field matches our query type - * (this may be redundant). - * We don't check the owner (apparently this is the - * name on the record) -- we assume that it matches - * or we would not have been given this SIG in the - * Answer Section. - * - * We only look on first pass, and only if we've something - * to learn. This cuts down on useless decoding. - */ - if (!doit && *dns_auth_level == DAL_UNSIGNED) - { - struct sig_rdata sr; - - if (!in_struct(&sr, &sig_rdata_desc, pbs, NULL)) - ugh = "failed to get fixed part of SIG Resource Record RDATA"; - else if (sr.type_covered == type) - *dns_auth_level = DAL_SIGNED; - } - break; - default: - ugh = builddiag("unexpected RR type %d", type); - break; - } - if (ugh != NULL) - return ugh; - } - in_raw(NULL, tail, pbs, "RR RDATA"); - } - - return doit - && cr->gateways_from_dns == NULL -#ifdef USE_KEYRR - && cr->keys_from_dns == NULL -#endif /* USE_KEYRR */ - ? builddiag("no suitable %s record found in DNS", rr_typename(type)) - : NULL; -} - -/* process DNS answer -- TXT or KEY query */ - -static err_t -process_dns_answer(struct adns_continuation *const cr -, u_char ans[], int anslen) -{ - const int type = cr->query.type; /* type of record being sought */ - int r; /* all-purpose return value holder */ - u_int16_t c; /* number of current RR in current answer section */ - pb_stream pbs; - u_int8_t *ans_start; /* saved position of answer section */ - struct qr_header qr_header; - enum dns_auth_level dns_auth_level; - - init_pbs(&pbs, ans, anslen, "Query Response Message"); - - /* decode and check header */ - - if (!in_struct(&qr_header, &qr_header_desc, &pbs, NULL)) - return "malformed header"; - - /* ID: nothing to do with us */ - - /* stuff -- lots of things */ - if ((qr_header.stuff & QRS_QR) == 0) - return "not a response?!?"; - - if (((qr_header.stuff >> QRS_OPCODE_SHIFT) & QRS_OPCODE_MASK) != QRSO_QUERY) - return "unexpected opcode"; - - /* I don't think we care about AA */ - - if (qr_header.stuff & QRS_TC) - return "response truncated"; - - /* I don't think we care about RD, RA, or CD */ - - /* AD means "authentic data" */ - dns_auth_level = qr_header.stuff & QRS_AD? DAL_UNSIGNED : DAL_NOTSEC; - - if (qr_header.stuff & QRS_Z) - return "Z bit is not zero"; - - r = (qr_header.stuff >> QRS_RCODE_SHIFT) & QRS_RCODE_MASK; - if (r != 0) - return r < (int)countof(rcode_text)? rcode_text[r] : "unknown rcode"; - - if (qr_header.ancount == 0) - return builddiag("no %s RR found by DNS", rr_typename(type)); - - /* end of header checking */ - - /* Question Section processing */ - - /* 4.1.2. Question section format: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / QNAME / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QTYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QCLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - - DBG(DBG_DNS, DBG_log("*Question Section:")); - - for (c = 0; c != qr_header.qdcount; c++) - { - struct qs_fixed qsf; - - TRY(eat_name_helpfully(&pbs, "Question Section")); - - if (!in_struct(&qsf, &qs_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Question Section"; - - if (qsf.qtype != type) - return "unexpected QTYPE in Question Section"; - - if (qsf.qclass != C_IN) - return "unexpected QCLASS in Question Section"; - } - - /* rest of sections are made up of Resource Records */ - - /* Answer Section processing -- error checking, noting T_SIG */ - - ans_start = pbs.cur; /* remember start of answer section */ - - TRY(process_answer_section(&pbs, FALSE, &dns_auth_level - , qr_header.ancount, cr)); - - /* Authority Section processing (just sanity checking) */ - - DBG(DBG_DNS, DBG_log("*Authority Section:")); - - for (c = 0; c != qr_header.nscount; c++) - { - struct rr_fixed rrf; - size_t tail; - - TRY(eat_name_helpfully(&pbs, "Authority Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Authority Section Resource Record"; - - if (rrf.rdlength > pbs_left(&pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - in_raw(NULL, tail, &pbs, "RR RDATA"); - } - - /* Additional Section processing (just sanity checking) */ - - DBG(DBG_DNS, DBG_log("*Additional Section:")); - - for (c = 0; c != qr_header.arcount; c++) - { - struct rr_fixed rrf; - size_t tail; - - TRY(eat_name_helpfully(&pbs, "Additional Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Additional Section Resource Record"; - - if (rrf.rdlength > pbs_left(&pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - in_raw(NULL, tail, &pbs, "RR RDATA"); - } - - /* done all sections */ - - /* ??? is padding legal, or can we complain if more left in record? */ - - /* process Answer Section again -- accept contents */ - - pbs.cur = ans_start; /* go back to start of answer section */ - - return process_answer_section(&pbs, TRUE, &dns_auth_level - , qr_header.ancount, cr); -} - -/****************************************************************/ - -static err_t build_dns_name(u_char name_buf[NS_MAXDNAME + 2], - unsigned long serial USED_BY_DEBUG, - identification_t *id, - const char *typename USED_BY_DEBUG, - identification_t *gw USED_BY_DEBUG) -{ - /* note: all end in "." to suppress relative searches */ - id = resolve_myid(id); - - switch (id->get_type(id)) - { - case ID_IPV4_ADDR: - { - chunk_t b = id->get_encoding(id); - - snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa.", - b.ptr[3], b.ptr[2], b.ptr[1], b.ptr[0]); - break; - } - case ID_IPV6_ADDR: - { - chunk_t b = id->get_encoding(id); - size_t bl; - u_char *op = name_buf; - static const char suffix[] = "IP6.INT."; - - for (bl = b.len; bl-- != 0; ) - { - if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1) - { - return "IPv6 reverse name too long"; - } - op += sprintf(op, "%x.%x.", b.ptr[bl] & 0xF, b.ptr[bl] >> 4); - } - strcpy(op, suffix); - break; - } - case ID_FQDN: - { - if (snprintf(name_buf, NS_MAXDNAME + 2, "%Y.", id) > NS_MAXDNAME + 1) - { - return "FQDN too long for domain name"; - } - break; - } - default: - return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR"; - } - - DBG(DBG_CONTROL | DBG_DNS, - DBG_log("DNS query %lu for %s for %s (gw: %Y)", serial, typename, name_buf, gw) - ) - return NULL; -} - -void gw_addref(struct gw_info *gw) -{ - if (gw != NULL) - { - DBG(DBG_DNS, DBG_log("gw_addref: %p refcnt: %d++", gw, gw->refcnt)) - gw->refcnt++; - } -} - -void gw_delref(struct gw_info **gwp) -{ - struct gw_info *gw = *gwp; - - if (gw != NULL) - { - DBG(DBG_DNS, DBG_log("gw_delref: %p refcnt: %d--", gw, gw->refcnt)); - - passert(gw->refcnt != 0); - gw->refcnt--; - if (gw->refcnt == 0) - { - DESTROY_IF(gw->client_id); - DESTROY_IF(gw->gw_id); - if (gw->gw_key_present) - { - unreference_key(&gw->key); - } - gw_delref(&gw->next); - free(gw); /* trickery could make this a tail-call */ - } - *gwp = NULL; - } -} - -static int adns_in_flight = 0; /* queries outstanding */ - -/* Start an asynchronous DNS query. - * - * For KEY record, the result will be a list in cr->keys_from_dns. - * For TXT records, the result will be a list in cr->gateways_from_dns. - * - * If sgw_id is null, only consider TXT records that specify an - * IP address for the gatway: we need this in the initiation case. - * - * If sgw_id is non-null, only consider TXT records that specify - * this id as the security gatway; this is useful to the Responder - * for confirming claims of gateways. - * - * Continuation cr gives information for continuing when the result shows up. - * - * Two kinds of errors must be handled: synchronous (immediate) - * and asynchronous. Synchronous errors are indicated by the returned - * value of start_adns_query; in this case, the continuation will - * have been freed and the continuation routine will not be called. - * Asynchronous errors are indicated by the ugh parameter passed to the - * continuation routine. - * - * After the continuation routine has completed, handle_adns_answer - * will free the continuation. The continuation routine should have - * freed any axiliary resources. - * - * Note: in the synchronous error case, start_adns_query will have - * freed the continuation; this means that the caller will have to - * be very careful to release any auxiliary resources that were in - * the continuation record without using the continuation record. - * - * Either there will be an error result passed to the continuation routine, - * or the results will be in cr->keys_from_dns or cr->gateways_from_dns. - * The result variables must by left NULL by the continutation routine. - * The continuation routine is responsible for establishing and - * disestablishing any logging context (whack_log_fd, cur_*). - */ - -static struct adns_continuation *continuations = NULL; /* newest of queue */ -static struct adns_continuation *next_query = NULL; /* oldest not sent */ - -static struct adns_continuation *continuation_for_qtid(unsigned long qtid) -{ - struct adns_continuation *cr = NULL; - - if (qtid != 0) - { - for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous) - ; - } - return cr; -} - -static void release_adns_continuation(struct adns_continuation *cr) -{ - passert(cr != next_query); - gw_delref(&cr->gateways_from_dns); -#ifdef USE_KEYRR - free_public_keys(&cr->keys_from_dns); -#endif /* USE_KEYRR */ - cr->id = cr->id->clone(cr->id); - cr->sgw_id = cr->sgw_id->clone(cr->sgw_id); - - /* unlink from doubly-linked list */ - if (cr->next == NULL) - { - continuations = cr->previous; - } - else - { - cr->next->previous = cr->previous; - } - - if (cr->previous != NULL) - { - cr->previous->next = cr->next; - } - - free(cr); -} - -err_t start_adns_query(identification_t *id, /* domain to query */ - identification_t *sgw_id, /* if non-null, any accepted gw_info must match */ - int type, /* T_TXT or T_KEY, selecting rr type of interest */ - cont_fn_t cont_fn, - struct adns_continuation *cr) -{ - static unsigned long qtid = 1; /* query transaction id; NOTE: static */ - const char *typename = rr_typename(type); - - if(adns_pid == 0 && adns_restart_count < ADNS_RESTART_MAX) - { - plog("ADNS helper was not running. Restarting attempt %d",adns_restart_count); - init_adns(); - } - - /* Splice this in at head of doubly-linked list of continuations. - * Note: this must be done before any release_adns_continuation(). - */ - cr->next = NULL; - cr->previous = continuations; - if (continuations != NULL) - { - continuations->next = cr; - } - continuations = cr; - - cr->qtid = qtid++; - cr->type = type; - cr->cont_fn = cont_fn; - cr->id = id->clone(id); - cr->sgw_specified = (sgw_id != NULL); - cr->sgw_id = cr->sgw_specified ? - sgw_id->clone(sgw_id) : - identification_create_from_string("%any"); - cr->gateways_from_dns = NULL; -#ifdef USE_KEYRR - cr->keys_from_dns = NULL; -#endif /* USE_KEYRR */ - -#ifdef DEBUG - cr->debugging = cur_debugging; -#else - cr->debugging = LEMPTY; -#endif - - zero(&cr->query); - { - err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid, id, - typename, cr->sgw_id); - - if (ugh) - { - release_adns_continuation(cr); - return ugh; - } - } - - if (next_query == NULL) - next_query = cr; - - unsent_ADNS_queries = TRUE; - - return NULL; -} - -/* send remaining ADNS queries (until pipe full or none left) - * - * This is a co-routine, so it uses static variables to - * preserve state across calls. - */ -bool unsent_ADNS_queries = FALSE; - -void -send_unsent_ADNS_queries(void) -{ - static const unsigned char *buf_end = NULL; /* NOTE STATIC */ - static const unsigned char *buf_cur = NULL; /* NOTE STATIC */ - - if (adns_qfd == NULL_FD) - return; /* nothing useful to do */ - - for (;;) - { - if (buf_cur != buf_end) - { - static int try = 0; /* NOTE STATIC */ - size_t n = buf_end - buf_cur; - ssize_t r = write(adns_qfd, buf_cur, n); - - if (r == -1) - { - switch (errno) - { - case EINTR: - continue; /* try again now */ - case EAGAIN: - DBG(DBG_DNS, DBG_log("EAGAIN writing to ADNS")); - break; /* try again later */ - default: - try++; - log_errno((e, "error %d writing DNS query", try)); - break; /* try again later */ - } - unsent_ADNS_queries = TRUE; - break; /* done! */ - } - else - { - passert(r >= 0); - try = 0; - buf_cur += r; - } - } - else - { - if (next_query == NULL) - { - unsent_ADNS_queries = FALSE; - break; /* done! */ - } - - next_query->query.debugging = next_query->debugging; - next_query->query.serial = next_query->qtid; - next_query->query.len = sizeof(next_query->query); - next_query->query.qmagic = ADNS_Q_MAGIC; - next_query->query.type = next_query->type; - buf_cur = (const void *)&next_query->query; - buf_end = buf_cur + sizeof(next_query->query); - - next_query = next_query->next; - adns_in_flight++; - } - } -} - -static void recover_adns_die(void) -{ - struct adns_continuation *cr = NULL; - - adns_pid = 0; - if(adns_restart_count < ADNS_RESTART_MAX) { - adns_restart_count++; - - /* next DNS query will restart it */ - - /* we have to walk the list of the outstanding requests, - * and redo them! - */ - - cr = continuations; - - /* find the head of the list */ - if(continuations != NULL) { - for (; cr->previous != NULL; cr = cr->previous); - } - - next_query = cr; - - if(next_query != NULL) { - unsent_ADNS_queries = TRUE; - } - } -} - -void reset_adns_restart_count(void) -{ - adns_restart_count=0; -} - -void handle_adns_answer(void) -{ - /* These are retained across calls to handle_adns_answer. */ - static size_t buflen = 0; /* bytes in answer buffer */ - static struct adns_answer buf; - - ssize_t n; - - passert(buflen < sizeof(buf)); - n = read(adns_afd, (unsigned char *)&buf + buflen, sizeof(buf) - buflen); - - if (n < 0) - { - if (errno != EINTR) - { - log_errno((e, "error reading answer from adns")); - /* ??? how can we recover? */ - } - n = 0; /* now n reflects amount read */ - } - else if (n == 0) - { - /* EOF */ - if (adns_in_flight != 0) - { - plog("EOF from ADNS with %d queries outstanding (restarts %d)" - , adns_in_flight, adns_restart_count); - recover_adns_die(); - } - if (buflen != 0) - { - plog("EOF from ADNS with %lu bytes of a partial answer outstanding" - "(restarts %d)" - , (unsigned long)buflen - , adns_restart_count); - recover_adns_die(); - } - stop_adns(); - return; - } - else - { - passert(adns_in_flight > 0); - } - - buflen += n; - while (buflen >= offsetof(struct adns_answer, ans) && buflen >= buf.len) - { - /* we've got a tasty answer -- process it */ - err_t ugh; - struct adns_continuation *cr = continuation_for_qtid(buf.serial); /* assume it works */ - const char *typename = rr_typename(cr->query.type); - const char *name_buf = cr->query.name_buf; - -#ifdef USE_KEYRR - passert(cr->keys_from_dns == NULL); -#endif /* USE_KEYRR */ - passert(cr->gateways_from_dns == NULL); - adns_in_flight--; - if (buf.result == -1) - { - /* newer resolvers support statp->res_h_errno as well as h_errno. - * That might be better, but older resolvers don't. - * See resolver(3), if you have it. - * The undocumented(!) h_errno values are defined in - * /usr/include/netdb.h. - */ - switch (buf.h_errno_val) - { - case NO_DATA: - ugh = builddiag("no %s record for %s", typename, name_buf); - break; - case HOST_NOT_FOUND: - ugh = builddiag("no host %s for %s record", name_buf, typename); - break; - default: - ugh = builddiag("failure querying DNS for %s of %s: %s" - , typename, name_buf, hstrerror(buf.h_errno_val)); - break; - } - } - else if (buf.result > (int) sizeof(buf.ans)) - { - ugh = builddiag("(INTERNAL ERROR) answer too long (%ld) for buffer" - , (long)buf.result); - } - else - { - ugh = process_dns_answer(cr, buf.ans, buf.result); - if (ugh != NULL) - ugh = builddiag("failure processing %s record of DNS answer for %s: %s" - , typename, name_buf, ugh); - } - DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS, - DBG_log(BLANK_FORMAT); - if (ugh == NULL) - DBG_log("asynch DNS answer %lu for %s of %s" - , cr->query.serial, typename, name_buf); - else - DBG_log("asynch DNS answer %lu %s", cr->query.serial, ugh); - ); - - passert(GLOBALS_ARE_RESET()); - cr->cont_fn(cr, ugh); - reset_globals(); - release_adns_continuation(cr); - - /* shift out answer that we've consumed */ - buflen -= buf.len; - memmove((unsigned char *)&buf, (unsigned char *)&buf + buf.len, buflen); - } -} diff --git a/src/pluto/dnskey.h b/src/pluto/dnskey.h deleted file mode 100644 index 39a406cbd..000000000 --- a/src/pluto/dnskey.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Find public key in DNS - * Copyright (C) 2000-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -extern int adns_qfd; /* file descriptor for sending queries to adns */ -extern int adns_afd; /* file descriptor for receiving answers from adns */ -extern const char *pluto_adns_option; /* path from --pluto_adns */ -extern void init_adns(void); -extern void stop_adns(void); -extern void handle_adns_answer(void); - -extern bool unsent_ADNS_queries; -extern void send_unsent_ADNS_queries(void); - -/* (common prefix of) stuff remembered between async query and answer. - * Filled in by start_adns_query. - * Freed by call to release_adns_continuation. - */ - -struct adns_continuation; /* forward declaration (not far!) */ - -typedef void (*cont_fn_t)(struct adns_continuation *cr, err_t ugh); - -struct adns_continuation { - unsigned long qtid; /* query transaction id number */ - int type; /* T_TXT or T_KEY, selecting rr type of interest */ - cont_fn_t cont_fn; /* function to carry on suspended work */ - identification_t *id; /* subject of query */ - bool sgw_specified; - identification_t *sgw_id; /* peer, if constrained */ - lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ - struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */ -#ifdef USE_KEYRR - struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */ -#endif - struct adns_continuation *previous, *next; - struct pubkey *last_info; /* the last structure we accumulated */ - struct adns_query query; -}; - -extern err_t start_adns_query(identification_t *id /* domain to query */ - , identification_t *sgw_id /* if non-null, any accepted gw_info must match */ - , int type /* T_TXT or T_KEY, selecting rr type of interest */ - , cont_fn_t cont_fn /* continuation function */ - , struct adns_continuation *cr); - - -/* Gateway info gleaned from reverse DNS of client */ -struct gw_info { - unsigned refcnt; /* reference counted! */ - unsigned pref; /* preference: lower is better */ -#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */ - identification_t* client_id; /* id of client of peer */ - identification_t* gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */ - bool gw_key_present; - struct pubkey *key; - struct gw_info *next; -}; - -extern void gw_addref(struct gw_info *gw); -extern void gw_delref(struct gw_info **gwp); -extern void reset_adns_restart_count(void); - diff --git a/src/pluto/event_queue.c b/src/pluto/event_queue.c deleted file mode 100644 index 602a013ee..000000000 --- a/src/pluto/event_queue.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include "event_queue.h" - -#include -#include -#include - -typedef struct private_event_queue_t private_event_queue_t; - -/** - * Private data of event_queue_t class. - */ -struct private_event_queue_t { - /** - * Public event_queue_t interface. - */ - event_queue_t public; - - /** - * List of queued events (event_t*). - */ - linked_list_t *events; - - /** - * Mutex for event list. - */ - mutex_t *mutex; - - /** - * Read end of the notification pipe. - */ - int read_fd; - - /** - * Write end of the notification pipe. - */ - int write_fd; - -}; - -typedef struct event_t event_t; - -struct event_t { - /** - * Callback function. - */ - void (*callback)(void *data); - - /** - * Data to supply to the callback. - */ - void *data; - - /** - * Cleanup function. - */ - void (*cleanup)(void *data); -}; - -static event_t *event_create(void (*callback)(void *data), void *data, - void (*cleanup)(void *data)) -{ - event_t *this; - INIT(this, - .callback = callback, - .data = data, - .cleanup = cleanup, - ); - return this; -} - -static void event_destroy(event_t *this) -{ - if (this->cleanup) - { - this->cleanup(this->data); - } - free(this); -} - -METHOD(event_queue_t, get_event_fd, int, - private_event_queue_t *this) -{ - return this->read_fd; -} - -METHOD(event_queue_t, handle, void, - private_event_queue_t *this) -{ - char buf[10]; - linked_list_t *events; - event_t *event; - this->mutex->lock(this->mutex); - /* flush pipe */ - while (read(this->read_fd, &buf, sizeof(buf)) == sizeof(buf)); - /* replace the list, so we can unlock the mutex while executing the jobs */ - events = this->events; - this->events = linked_list_create(); - this->mutex->unlock(this->mutex); - - while (events->remove_first(events, (void**)&event) == SUCCESS) - { - event->callback(event->data); - event_destroy(event); - } - events->destroy(events); -} - -METHOD(event_queue_t, queue, void, - private_event_queue_t *this, void (*callback)(void *data), void *data, - void (*cleanup)(void *data)) -{ - event_t *event = event_create(callback, data, cleanup); - char c = 0; - this->mutex->lock(this->mutex); - this->events->insert_last(this->events, event); - ignore_result(write(this->write_fd, &c, 1)); - this->mutex->unlock(this->mutex); -} - -METHOD(event_queue_t, destroy, void, - private_event_queue_t *this) -{ - this->mutex->lock(this->mutex); - this->events->destroy_function(this->events, (void*)event_destroy); - this->mutex->unlock(this->mutex); - this->mutex->destroy(this->mutex); - close(this->read_fd); - close(this->write_fd); - free(this); -} - -static bool set_nonblock(int socket) -{ - int flags = fcntl(socket, F_GETFL); - return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1; -} - -static bool set_cloexec(int socket) -{ - int flags = fcntl(socket, F_GETFD); - return flags != -1 && fcntl(socket, F_SETFD, flags | FD_CLOEXEC) != -1; -} - -/* - * Described in header. - */ -event_queue_t *event_queue_create() -{ - private_event_queue_t *this; - int fd[2]; - - INIT(this, - .public = { - .get_event_fd = _get_event_fd, - .handle = _handle, - .queue = _queue, - .destroy = _destroy, - }, - .events = linked_list_create(), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - ); - - if (pipe(fd) == -1 || - !set_nonblock(fd[0]) || !set_cloexec(fd[0]) || - !set_nonblock(fd[1]) || !set_cloexec(fd[1])) - { - DBG1(DBG_JOB, "failed to create pipe for job queue"); - _destroy(this); - return NULL; - } - - this->read_fd = fd[0]; - this->write_fd = fd[1]; - - return &this->public; -} - diff --git a/src/pluto/event_queue.h b/src/pluto/event_queue.h deleted file mode 100644 index 343729e25..000000000 --- a/src/pluto/event_queue.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup event_queue event_queue - * @{ @ingroup pluto - */ - -#ifndef EVENT_QUEUE_H_ -#define EVENT_QUEUE_H_ - -typedef struct event_queue_t event_queue_t; - -/** - * The event queue facility can be used to synchronize thread-pool threads - * with the pluto main thread. That is, all queued callbacks are executed - * asynchronously by the pluto main thread. - */ -struct event_queue_t { - - /** - * Returns the file descriptor used to notify the main thread. - * - * @return fd to use in the main thread - */ - int (*get_event_fd) (event_queue_t *this); - - /** - * Handle all queued events. - */ - void (*handle) (event_queue_t *this); - - /** - * Add an event to the queue. - * - * @param callback callback function to add to the queue - * @param data data supplied to the callback function - * @param cleanup optional cleanup function - */ - void (*queue) (event_queue_t *this, void (*callback)(void *data), - void *data, void (*cleanup)(void *data)); - - /** - * Destroy this instance. - */ - void (*destroy) (event_queue_t *this); - -}; - -/** - * Create the event queue. - * - * @return created object - */ -event_queue_t *event_queue_create(); - -#endif /** EVENT_QUEUE_H_ @}*/ diff --git a/src/pluto/fetch.c b/src/pluto/fetch.c deleted file mode 100644 index 3dfc1386f..000000000 --- a/src/pluto/fetch.c +++ /dev/null @@ -1,766 +0,0 @@ -/* Dynamic fetching of X.509 CRLs - * Copyright (C) 2002 Stephane Laroche - * Copyright (C) 2002-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#ifdef THREADS -#include -#endif - -#include - -#include -#include -#include -#include -#ifdef THREADS -#include -#endif - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "ca.h" -#include "whack.h" -#include "ocsp.h" -#include "crl.h" -#include "fetch.h" -#include "builder.h" - -fetch_req_t empty_fetch_req = { - NULL , /* next */ - 0 , /* trials */ - NULL , /* issuer */ - { NULL, 0}, /* authKeyID */ - NULL /* distributionPoints */ -}; - -/* chained list of crl fetch requests */ -static fetch_req_t *crl_fetch_reqs = NULL; - -/* chained list of ocsp fetch requests */ -static ocsp_location_t *ocsp_fetch_reqs = NULL; - -#ifdef THREADS -static thread_t *thread; -static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ca_info_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER; - -/** - * lock access to my certs and keys - */ -void lock_certs_and_keys(const char *who) -{ - pthread_mutex_lock(&certs_and_keys_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("certs and keys locked by '%s'", who) - ) -} - -/** - * Unlock access to my certs and keys - */ -void unlock_certs_and_keys(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("certs and keys unlocked by '%s'", who) - ) - pthread_mutex_unlock(&certs_and_keys_mutex); -} - -/** - * Lock access to the chained authcert list - */ -void lock_authcert_list(const char *who) -{ - pthread_mutex_lock(&authcert_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("authcert list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained authcert list - */ -void unlock_authcert_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("authcert list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&authcert_list_mutex); -} - -/** - * Lock access to the chained crl list - */ -void lock_crl_list(const char *who) -{ - pthread_mutex_lock(&crl_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("crl list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained crl list - */ -void unlock_crl_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("crl list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&crl_list_mutex); -} - -/** - * Lock access to the ocsp cache - */ -extern void lock_ocsp_cache(const char *who) -{ - pthread_mutex_lock(&ocsp_cache_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ocsp cache locked by '%s'", who) - ) -} - -/** - * Unlock access to the ocsp cache - */ -extern void unlock_ocsp_cache(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ocsp cache unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ocsp_cache_mutex); -} - -/** - * Lock access to the ca info list - */ -extern void lock_ca_info_list(const char *who) -{ - pthread_mutex_lock(&ca_info_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ca info list locked by '%s'", who) - ) -} - -/** - * Unlock access to the ca info list - */ -extern void unlock_ca_info_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ca info list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ca_info_list_mutex); -} - -/** - * Lock access to the chained crl fetch request list - */ -static void lock_crl_fetch_list(const char *who) -{ - pthread_mutex_lock(&crl_fetch_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("crl fetch request list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained crl fetch request list - */ -static void unlock_crl_fetch_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("crl fetch request list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&crl_fetch_list_mutex); -} - -/** - * Lock access to the chained ocsp fetch request list - */ -static void lock_ocsp_fetch_list(const char *who) -{ - pthread_mutex_lock(&ocsp_fetch_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ocsp fetch request list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained ocsp fetch request list - */ -static void unlock_ocsp_fetch_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ocsp fetch request list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ocsp_fetch_list_mutex); -} - -/** - * Wakes up the sleeping fetch thread - */ -void wake_fetch_thread(const char *who) -{ - if (crl_check_interval > 0) - { - DBG(DBG_CONTROLMORE, - DBG_log("fetch thread wake call by '%s'", who) - ) - pthread_mutex_lock(&fetch_wake_mutex); - pthread_cond_signal(&fetch_wake_cond); - pthread_mutex_unlock(&fetch_wake_mutex); - } -} -#else /* !THREADS */ -#define lock_crl_fetch_list(who) /* do nothing */ -#define unlock_crl_fetch_list(who) /* do nothing */ -#define lock_ocsp_fetch_list(who) /* do nothing */ -#define unlock_ocsp_fetch_list(who) /* do nothing */ -#endif /* !THREADS */ - -/** - * Free the dynamic memory used to store fetch requests - */ -static void free_fetch_request(fetch_req_t *req) -{ - req->distributionPoints->destroy_function(req->distributionPoints, free); - DESTROY_IF(req->issuer); - free(req->authKeyID.ptr); - free(req); -} - -#ifdef THREADS -/** - * Fetch an ASN.1 blob coded in PEM or DER format from a URL - */ -x509crl_t* fetch_crl(char *url) -{ - x509crl_t *crl; - chunk_t blob; - - DBG1(DBG_LIB, " fetching crl from '%s' ...", url); - if (lib->fetcher->fetch(lib->fetcher, url, &blob, FETCH_END) != SUCCESS) - { - DBG1(DBG_LIB, "crl fetching failed"); - return FALSE; - } - crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, - BUILD_BLOB_PEM, blob, BUILD_END); - free(blob.ptr); - if (!crl) - { - DBG1(DBG_LIB, "crl fetched successfully but data coded in unknown " - "format"); - } - return crl; -} - -/** - * Complete a distributionPoint URI with ca information - */ -static char* complete_uri(char *distPoint, const char *ldaphost) -{ - char *symbol = strchr(distPoint, ':'); - - if (symbol) - { - int type_len = symbol - distPoint; - - if (type_len >= 4 && strncasecmp(distPoint, "ldap", 4) == 0) - { - char *ptr = symbol + 1; - int len = strlen(distPoint) - (type_len + 1); - - if (len > 2 && *ptr++ == '/' && *ptr++ == '/') - { - len -= 2; - symbol = strchr(ptr, '/'); - - if (symbol && symbol - ptr == 0 && ldaphost) - { - char uri[BUF_LEN]; - - /* insert the ldaphost into the uri */ - snprintf(uri, BUF_LEN, "%.*s%s%.*s", - (int)strlen(distPoint) - len, distPoint, ldaphost, - len, symbol); - return strdup(uri); - } - } - } - } - - /* default action: copy distributionPoint without change */ - return strdup(distPoint); -} - -/** - * Try to fetch the crls defined by the fetch requests - */ -static void fetch_crls(bool cache_crls) -{ - fetch_req_t *req; - fetch_req_t **reqp; - - lock_crl_fetch_list("fetch_crls"); - req = crl_fetch_reqs; - reqp = &crl_fetch_reqs; - - while (req != NULL) - { - enumerator_t *enumerator; - char *point; - bool valid_crl = FALSE; - const char *ldaphost; - ca_info_t *ca; - - lock_ca_info_list("fetch_crls"); - - ca = get_ca_info(req->issuer, req->authKeyID); - ldaphost = (ca == NULL)? NULL : ca->ldaphost; - - enumerator = req->distributionPoints->create_enumerator(req->distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - x509crl_t *crl; - char *uri; - - uri = complete_uri(point, ldaphost); - crl = fetch_crl(uri); - free(uri); - - if (crl) - { - if (insert_crl(crl, point, cache_crls)) - { - DBG(DBG_CONTROL, - DBG_log("we have a valid crl") - ) - valid_crl = TRUE; - break; - } - } - } - enumerator->destroy(enumerator); - unlock_ca_info_list("fetch_crls"); - - if (valid_crl) - { - /* delete fetch request */ - fetch_req_t *req_free = req; - - req = req->next; - *reqp = req; - free_fetch_request(req_free); - } - else - { - /* try again next time */ - req->trials++; - reqp = &req->next; - req = req->next; - } - } - unlock_crl_fetch_list("fetch_crls"); -} - -static void fetch_ocsp_status(ocsp_location_t* location) -{ - chunk_t request = build_ocsp_request(location); - chunk_t response = chunk_empty; - - DBG1(DBG_LIB, " requesting ocsp status from '%s' ...", location->uri); - if (lib->fetcher->fetch(lib->fetcher, location->uri, &response, - FETCH_REQUEST_DATA, request, - FETCH_REQUEST_TYPE, "application/ocsp-request", - FETCH_END) == SUCCESS) - { - parse_ocsp(location, response); - } - else - { - DBG1(DBG_LIB, "ocsp request to %s failed", location->uri); - } - - free(request.ptr); - chunk_free(&location->nonce); - - /* increment the trial counter of the unresolved fetch requests */ - { - ocsp_certinfo_t *certinfo = location->certinfo; - - while (certinfo != NULL) - { - certinfo->trials++; - certinfo = certinfo->next; - } - } -} - -/** - * Try to fetch the necessary ocsp information - */ -static void fetch_ocsp(void) -{ - ocsp_location_t *location; - - lock_ocsp_fetch_list("fetch_ocsp"); - location = ocsp_fetch_reqs; - - /* fetch the ocps status for all locations */ - while (location != NULL) - { - if (location->certinfo != NULL) - { - fetch_ocsp_status(location); - } - location = location->next; - } - - unlock_ocsp_fetch_list("fetch_ocsp"); -} - -static void* fetch_thread(void *arg) -{ - struct timespec wait_interval; - - /* the fetching thread is only cancellable while waiting for new events */ - thread_cancelability(FALSE); - - DBG(DBG_CONTROL, - DBG_log("fetch thread started") - ) - - pthread_mutex_lock(&fetch_wake_mutex); - - while(1) - { - int status; - - wait_interval.tv_nsec = 0; - wait_interval.tv_sec = time(NULL) + crl_check_interval; - - DBG(DBG_CONTROL, - DBG_log("next regular crl check in %ld seconds", crl_check_interval) - ) - - thread_cancelability(TRUE); - status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex - , &wait_interval); - thread_cancelability(FALSE); - - if (status == ETIMEDOUT) - { - DBG(DBG_CONTROL, - DBG_log(" "); - DBG_log("*time to check crls and the ocsp cache") - ) - check_ocsp(); - check_crls(); - } - else - { - DBG(DBG_CONTROL, - DBG_log("fetch thread was woken up") - ) - } - fetch_ocsp(); - fetch_crls(cache_crls); - } - return NULL; -} -#endif /* THREADS*/ - -/** - * Initializes curl and starts the fetching thread - */ -void fetch_initialize(void) -{ - if (crl_check_interval > 0) - { -#ifdef THREADS - thread = thread_create((thread_main_t)fetch_thread, NULL); - if (thread == NULL) - { - plog("fetching thread could not be started"); - } -#else /* !THREADS */ - plog("warning: not compiled with pthread support"); -#endif /* !THREADS */ - } -} - -/** - * Terminates the fetching thread - */ -void fetch_finalize(void) -{ - if (crl_check_interval > 0) - { -#ifdef THREADS - if (thread) - { - thread->cancel(thread); - thread->join(thread); - } -#endif - } -} - -void free_crl_fetch(void) -{ - lock_crl_fetch_list("free_crl_fetch"); - - while (crl_fetch_reqs != NULL) - { - fetch_req_t *req = crl_fetch_reqs; - crl_fetch_reqs = req->next; - free_fetch_request(req); - } - - unlock_crl_fetch_list("free_crl_fetch"); -} - -/** - * Free the chained list of ocsp requests - */ -void free_ocsp_fetch(void) -{ - lock_ocsp_fetch_list("free_ocsp_fetch"); - free_ocsp_locations(&ocsp_fetch_reqs); - unlock_ocsp_fetch_list("free_ocsp_fetch"); -} - - -/** - * Add an additional distribution point - */ -void add_distribution_point(linked_list_t *points, char *new_point) -{ - char *point; - bool add = TRUE; - enumerator_t *enumerator; - - if (new_point == NULL || *new_point == '\0') - { - return; - } - - enumerator = points->create_enumerator(points); - while (enumerator->enumerate(enumerator, &point)) - { - if (streq(point, new_point)) - { - add = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (add) - { - points->insert_last(points, strdup(new_point)); - } -} - -/** - * Add additional distribution points - */ -void add_distribution_points(linked_list_t *points, linked_list_t *new_points) -{ - char *new_point; - enumerator_t *enumerator; - - enumerator = new_points->create_enumerator(new_points); - while (enumerator->enumerate(enumerator, &new_point)) - { - bool add = TRUE; - char *point; - enumerator_t *enumerator; - - enumerator = points->create_enumerator(points); - while (enumerator->enumerate(enumerator, &point)) - { - if (streq(point, new_point)) - { - add = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (add) - { - points->insert_last(points, strdup(new_point)); - } - } - enumerator->destroy(enumerator); -} - -fetch_req_t* build_crl_fetch_request(identification_t *issuer, - chunk_t authKeyID, - linked_list_t *distributionPoints) -{ - char *point; - enumerator_t *enumerator; - fetch_req_t *req = malloc_thing(fetch_req_t); - - memset(req, 0, sizeof(fetch_req_t)); - req->distributionPoints = linked_list_create(); - - /* clone fields */ - req->issuer = issuer->clone(issuer); - req->authKeyID = chunk_clone(authKeyID); - - /* copy distribution points */ - enumerator = distributionPoints->create_enumerator(distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - req->distributionPoints->insert_last(req->distributionPoints, - strdup(point)); - } - enumerator->destroy(enumerator); - - return req; -} - -/** - * Add a crl fetch request to the chained list - */ -void add_crl_fetch_request(fetch_req_t *req) -{ - fetch_req_t *r; - - lock_crl_fetch_list("add_crl_fetch_request"); - r = crl_fetch_reqs; - - while (r != NULL) - { - if (req->authKeyID.ptr ? same_keyid(req->authKeyID, r->authKeyID) : - req->issuer->equals(req->issuer, r->issuer)) - { - /* there is already a fetch request */ - DBG(DBG_CONTROL, - DBG_log("crl fetch request already exists") - ) - - /* there might be new distribution points */ - add_distribution_points(r->distributionPoints, - req->distributionPoints); - - unlock_crl_fetch_list("add_crl_fetch_request"); - free_fetch_request(req); - return; - } - r = r->next; - } - - /* insert new fetch request at the head of the queue */ - req->next = crl_fetch_reqs; - crl_fetch_reqs = req; - - DBG(DBG_CONTROL, - DBG_log("crl fetch request added") - ) - unlock_crl_fetch_list("add_crl_fetch_request"); -} - -/** - * Add an ocsp fetch request to the chained list - */ -void add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber) -{ - ocsp_certinfo_t certinfo; - - certinfo.serialNumber = serialNumber; - - lock_ocsp_fetch_list("add_ocsp_fetch_request"); - add_certinfo(location, &certinfo, &ocsp_fetch_reqs, TRUE); - unlock_ocsp_fetch_list("add_ocsp_fetch_request"); -} - -/** - * List all distribution points - */ -void list_distribution_points(linked_list_t *distributionPoints) -{ - char *point; - bool first_point = TRUE; - enumerator_t *enumerator; - - enumerator = distributionPoints->create_enumerator(distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - whack_log(RC_COMMENT, " %s '%s'", - (first_point)? "distPts: " : " ", point); - first_point = FALSE; - } - enumerator->destroy(enumerator); -} - -/** - * List all fetch requests in the chained list - */ -void list_crl_fetch_requests(bool utc) -{ - fetch_req_t *req; - - lock_crl_fetch_list("list_crl_fetch_requests"); - req = crl_fetch_reqs; - - if (req != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of CRL Fetch Requests:"); - } - - while (req != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " trials: %d", req->trials); - whack_log(RC_COMMENT, " issuer: \"%Y\"", req->issuer); - if (req->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &req->authKeyID); - } - list_distribution_points(req->distributionPoints); - req = req->next; - } - unlock_crl_fetch_list("list_crl_fetch_requests"); -} - -void list_ocsp_fetch_requests(bool utc) -{ - lock_ocsp_fetch_list("list_ocsp_fetch_requests"); - list_ocsp_locations(ocsp_fetch_reqs, TRUE, utc, FALSE); - unlock_ocsp_fetch_list("list_ocsp_fetch_requests"); - -} diff --git a/src/pluto/fetch.h b/src/pluto/fetch.h deleted file mode 100644 index 265dc5fe7..000000000 --- a/src/pluto/fetch.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Dynamic fetching of X.509 CRLs - * Copyright (C) 2002 Stephane Laroche - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include "x509.h" - -#define FETCH_CMD_TIMEOUT 10 /* seconds */ - -struct ocsp_location; /* forward declaration of ocsp_location defined in ocsp.h */ - -typedef enum { - FETCH_GET = 1, - FETCH_POST = 2 -} fetch_request_t; - -typedef struct fetch_req fetch_req_t; - -struct fetch_req { - fetch_req_t *next; - int trials; - identification_t *issuer; - chunk_t authKeyID; - linked_list_t *distributionPoints; -}; - -#ifdef THREADS -extern void lock_crl_list(const char *who); -extern void unlock_crl_list(const char *who); -extern void lock_ocsp_cache(const char *who); -extern void unlock_ocsp_cache(const char *who); -extern void lock_ca_info_list(const char *who); -extern void unlock_ca_info_list(const char *who); -extern void lock_authcert_list(const char *who); -extern void unlock_authcert_list(const char *who); -extern void lock_certs_and_keys(const char *who); -extern void unlock_certs_and_keys(const char *who); -extern void wake_fetch_thread(const char *who); -#else -#define lock_crl_list(who) /* do nothing */ -#define unlock_crl_list(who) /* do nothing */ -#define lock_ocsp_cache(who) /* do nothing */ -#define unlock_ocsp_cache(who) /* do nothing */ -#define lock_ca_info_list(who) /* do nothing */ -#define unlock_ca_info_list(who) /* do nothing */ -#define lock_authcert_list(who) /* do nothing */ -#define unlock_authcert_list(who) /* do nothing */ -#define lock_certs_and_keys(who) /* do nothing */ -#define unlock_certs_and_keys(who) /* do nothing */ -#define wake_fetch_thread(who) /* do nothing */ -#endif -extern void fetch_initialize(void); -extern void fetch_finalize(void); -extern void free_crl_fetch(void); -extern void free_ocsp_fetch(void); -extern void add_distribution_point(linked_list_t *points, char* new_point); -extern void add_distribution_points(linked_list_t *points, - linked_list_t *new_points); -extern fetch_req_t* build_crl_fetch_request(identification_t *issuer, - chunk_t authKeyID, - linked_list_t *distributionPoints); -extern void add_crl_fetch_request(fetch_req_t *req); -extern void add_ocsp_fetch_request(struct ocsp_location *location, - chunk_t serialNumber); -extern void list_distribution_points(linked_list_t *distributionPoints); -extern void list_crl_fetch_requests(bool utc); -extern void list_ocsp_fetch_requests(bool utc); -extern size_t write_buffer(void *ptr, size_t size, size_t nmemb, void *data); - diff --git a/src/pluto/foodgroups.c b/src/pluto/foodgroups.c deleted file mode 100644 index e4f9a1d01..000000000 --- a/src/pluto/foodgroups.c +++ /dev/null @@ -1,450 +0,0 @@ -/* Implement policy groups-style control files (aka "foodgroups") - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "foodgroups.h" -#include "kernel.h" -#include "lex.h" -#include "log.h" -#include "whack.h" - - -/* Food group config files are found in directory fg_path */ - -#ifndef POLICYGROUPSDIR -#define POLICYGROUPSDIR IPSEC_CONFDIR "/ipsec.d/policies" -#endif - -const char *policygroups_dir = POLICYGROUPSDIR; - -static char *fg_path = NULL; -static size_t fg_path_space = 0; - - -/* Groups is a list of connections that are policy groups. - * The list is updated as group connections are added and deleted. - */ - -struct fg_groups { - struct fg_groups *next; - connection_t *connection; -}; - -static struct fg_groups *groups = NULL; - - -/* Targets is a list of pairs: subnet and its policy group. - * This list is bulk-updated on whack --listen and - * incrementally updated when group connections are deleted. - * - * It is ordered by source subnet, and if those are equal, then target subnet. - * A subnet is compared by comparing the network, and if those are equal, - * comparing the mask. - */ - -struct fg_targets { - struct fg_targets *next; - struct fg_groups *group; - ip_subnet subnet; - char *name; /* name of instance of group conn */ -}; - -static struct fg_targets *targets = NULL; - -struct fg_targets *new_targets; - -/* ipcmp compares the two ip_address values a and b. - * It returns -1, 0, or +1 if a is, respectively, - * less than, equal to, or greater than b. - */ -static int ipcmp(ip_address *a, ip_address *b) -{ - if (addrtypeof(a) != addrtypeof(b)) - { - return addrtypeof(a) < addrtypeof(b)? -1 : 1; - } - else if (sameaddr(a, b)) - { - return 0; - } - else - { - const struct sockaddr *sa = sockaddrof(a) - , *sb = sockaddrof(b); - - passert(addrtypeof(a) == AF_INET); /* not yet implemented IPv6 version :-( */ - return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr) - < ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr)) - ? -1 : 1; - } -} - -/* subnetcmp compares the two ip_subnet values a and b. - * It returns -1, 0, or +1 if a is, respectively, - * less than, equal to, or greater than b. - */ -static int subnetcmp(const ip_subnet *a, const ip_subnet *b) -{ - ip_address neta, maska, netb, maskb; - int r; - - networkof(a, &neta); - maskof(a, &maska); - networkof(b, &netb); - maskof(b, &maskb); - r = ipcmp(&neta, &netb); - if (r == 0) - r = ipcmp(&maska, &maskb); - return r; -} - -static void read_foodgroup(struct fg_groups *g) -{ - const char *fgn = g->connection->name; - const ip_subnet *lsn = &g->connection->spd.this.client; - size_t plen = strlen(policygroups_dir) + 1 + strlen(fgn) + 1; - struct file_lex_position flp_space; - - if (plen > fg_path_space) - { - free(fg_path); - fg_path_space = plen + 10; - fg_path = malloc(fg_path_space); - } - snprintf(fg_path, fg_path_space, "%s/%s", policygroups_dir, fgn); - if (!lexopen(&flp_space, fg_path, TRUE)) - { - DBG(DBG_CONTROL, DBG_log("no group file \"%s\"", fg_path)); - } - else - { - plog("loading group \"%s\"", fg_path); - for (;;) - { - switch (flp->bdry) - { - case B_none: - { - /* !!! this test is not sufficient for distinguishing address families. - * We need a notation to specify that a FQDN is to be resolved to IPv6. - */ - const struct af_info *afi = strchr(tok, ':') == NULL - ? &af_inet4_info: &af_inet6_info; - ip_subnet sn; - err_t ugh; - - if (strchr(tok, '/') == NULL) - { - /* no /, so treat as /32 or V6 equivalent */ - ip_address t; - - ugh = ttoaddr(tok, 0, afi->af, &t); - if (ugh == NULL) - ugh = addrtosubnet(&t, &sn); - } - else - { - ugh = ttosubnet(tok, 0, afi->af, &sn); - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s \"%s\"" - , flp->filename, flp->lino, ugh, tok); - } - else if (afi->af != AF_INET) - { - loglog(RC_LOG_SERIOUS - , "\"%s\" line %d: unsupported Address Family \"%s\"" - , flp->filename, flp->lino, tok); - } - else - { - /* Find where new entry ought to go in new_targets. */ - struct fg_targets **pp; - int r; - - for (pp = &new_targets; ; pp = &(*pp)->next) - { - if (*pp == NULL) - { - r = -1; /* end of list is infinite */ - break; - } - r = subnetcmp(lsn, &(*pp)->group->connection->spd.this.client); - if (r == 0) - r = subnetcmp(&sn, &(*pp)->subnet); - if (r <= 0) - break; - } - - if (r == 0) - { - char source[SUBNETTOT_BUF]; - - subnettot(lsn, 0, source, sizeof(source)); - loglog(RC_LOG_SERIOUS - , "\"%s\" line %d: subnet \"%s\", source %s, already \"%s\"" - , flp->filename - , flp->lino - , tok - , source - , (*pp)->group->connection->name); - } - else - { - struct fg_targets *f = malloc_thing(struct fg_targets); - - f->next = *pp; - f->group = g; - f->subnet = sn; - f->name = NULL; - *pp = f; - } - } - } - (void)shift(); /* next */ - continue; - - case B_record: - flp->bdry = B_none; /* eat the Record Boundary */ - (void)shift(); /* get real first token */ - continue; - - case B_file: - break; /* done */ - } - break; /* if we reach here, out of loop */ - } - lexclose(); - } -} - -static void free_targets(void) -{ - while (targets != NULL) - { - struct fg_targets *t = targets; - - targets = t->next; - free(t->name); - free(t); - } -} - -void load_groups(void) -{ - passert(new_targets == NULL); - - /* for each group, add config file targets into new_targets */ - { - struct fg_groups *g; - - for (g = groups; g != NULL; g = g->next) - if (oriented(*g->connection)) - read_foodgroup(g); - } - - /* dump new_targets */ - DBG(DBG_CONTROL, - { - struct fg_targets *t; - - for (t = new_targets; t != NULL; t = t->next) - { - char asource[SUBNETTOT_BUF]; - char atarget[SUBNETTOT_BUF]; - - subnettot(&t->group->connection->spd.this.client - , 0, asource, sizeof(asource)); - subnettot(&t->subnet, 0, atarget, sizeof(atarget)); - DBG_log("%s->%s %s" - , asource, atarget - , t->group->connection->name); - } - }); - - /* determine and deal with differences between targets and new_targets. - * structured like a merge. - */ - { - struct fg_targets *op = targets - , *np = new_targets; - - while (op != NULL && np != NULL) - { - int r = subnetcmp(&op->group->connection->spd.this.client - , &np->group->connection->spd.this.client); - - if (r == 0) - r = subnetcmp(&op->subnet, &np->subnet); - - if (r == 0 && op->group == np->group) - { - /* unchanged -- steal name & skip over */ - np->name = op->name; - op->name = NULL; - op = op->next; - np = np->next; - } - else - { - /* note: following cases overlap! */ - if (r <= 0) - { - remove_group_instance(op->group->connection, op->name); - op = op->next; - } - if (r >= 0) - { - np->name = add_group_instance(np->group->connection, &np->subnet); - np = np->next; - } - } - } - for (; op != NULL; op = op->next) - remove_group_instance(op->group->connection, op->name); - for (; np != NULL; np = np->next) - np->name = add_group_instance(np->group->connection, &np->subnet); - - /* update: new_targets replaces targets */ - free_targets(); - targets = new_targets; - new_targets = NULL; - } -} - - -void add_group(connection_t *c) -{ - struct fg_groups *g = malloc_thing(struct fg_groups); - - g->next = groups; - groups = g; - - g->connection = c; -} - -static struct fg_groups *find_group(const connection_t *c) -{ - struct fg_groups *g; - - for (g = groups; g != NULL && g->connection != c; g = g->next) - ; - return g; -} - -void route_group(connection_t *c) -{ - /* it makes no sense to route a connection that is ISAKMP-only */ - if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) - { - loglog(RC_ROUTE, "cannot route an ISAKMP-only group connection"); - } - else - { - struct fg_groups *g = find_group(c); - struct fg_targets *t; - - passert(g != NULL); - g->connection->policy |= POLICY_GROUTED; - for (t = targets; t != NULL; t = t->next) - { - if (t->group == g) - { - connection_t *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - if (!trap_connection(ci)) - whack_log(RC_ROUTE, "could not route"); - set_cur_connection(c); - } - } - } - } -} - -void unroute_group(connection_t *c) -{ - struct fg_groups *g = find_group(c); - struct fg_targets *t; - - passert(g != NULL); - g->connection->policy &= ~POLICY_GROUTED; - for (t = targets; t != NULL; t = t->next) - { - if (t->group == g) - { - connection_t *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - unroute_connection(ci); - set_cur_connection(c); - } - } - } -} - -void delete_group(const connection_t *c) -{ - struct fg_groups *g; - - /* find and remove from groups */ - { - struct fg_groups **pp; - - for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next) - ; - - *pp = g->next; - } - - /* find and remove from targets */ - { - struct fg_targets **pp; - - for (pp = &targets; *pp != NULL; ) - { - struct fg_targets *t = *pp; - - if (t->group == g) - { - *pp = t->next; - remove_group_instance(t->group->connection, t->name); - free(t); - /* pp is ready for next iteration */ - } - else - { - pp = &t->next; - } - } - } - - free(g); -} diff --git a/src/pluto/foodgroups.h b/src/pluto/foodgroups.h deleted file mode 100644 index b6d3386ae..000000000 --- a/src/pluto/foodgroups.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Implement policygroups-style control files (aka "foodgroups") - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -struct connection; /* forward declaration */ -extern void add_group(struct connection *c); -extern void route_group(struct connection *c); -extern void unroute_group(struct connection *c); -extern void delete_group(const struct connection *c); - -extern const char *policygroups_dir; -extern void load_groups(void); diff --git a/src/pluto/ike_alg.c b/src/pluto/ike_alg.c deleted file mode 100644 index 3061630e0..000000000 --- a/src/pluto/ike_alg.c +++ /dev/null @@ -1,452 +0,0 @@ -/* IKE modular algorithm handling interface - * Copyright (C) JuanJo Ciarlante - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "crypto.h" -#include "state.h" -#include "packet.h" -#include "keys.h" -#include "log.h" -#include "whack.h" -#include "spdb.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "db_ops.h" -#include "connections.h" -#include "kernel.h" - -#define return_on(var, val) do { var=val;goto return_out; } while(0); - -/** - * IKE algorithm list handling - registration and lookup - */ - -/* Modular IKE algorithm storage structure */ - -static struct ike_alg *ike_alg_base[IKE_ALG_MAX+1] = {NULL, NULL}; - -/** - * Return ike_algo object by {type, id} - */ -static struct ike_alg *ike_alg_find(u_int algo_type, u_int algo_id, - u_int keysize __attribute__((unused))) -{ - struct ike_alg *e = ike_alg_base[algo_type]; - - while (e != NULL && algo_id > e->algo_id) - { - e = e->algo_next; - } - return (e != NULL && e->algo_id == algo_id) ? e : NULL; -} - -/** - * "raw" ike_alg list adding function - */ -int ike_alg_add(struct ike_alg* a, const char *plugin_name) -{ - if (a->algo_type > IKE_ALG_MAX) - { - plog("ike_alg: Not added, invalid algorithm type"); - return -EINVAL; - } - - if (ike_alg_find(a->algo_type, a->algo_id, 0) != NULL) - { - plog("ike_alg: Not added, algorithm already exists"); - return -EEXIST; - } - - { - struct ike_alg **ep = &ike_alg_base[a->algo_type]; - struct ike_alg *e = *ep; - - while (e != NULL && a->algo_id > e->algo_id) - { - ep = &e->algo_next; - e = *ep; - } - *ep = a; - a->plugin_name = plugin_name; - a->algo_next = e; - return 0; - } -} - -/** - * Get IKE hash algorithm - */ -struct hash_desc *ike_alg_get_hasher(u_int alg) -{ - return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0); -} - -/** - * Get IKE encryption algorithm - */ -struct encrypt_desc *ike_alg_get_crypter(u_int alg) -{ - return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0); -} - -/** - * Get IKE dh group - */ -struct dh_desc *ike_alg_get_dh_group(u_int alg) -{ - return (struct dh_desc *) ike_alg_find(IKE_ALG_DH_GROUP, alg, 0); -} - -/** - * Get pfsgroup for this connection - */ -const struct dh_desc *ike_alg_pfsgroup(connection_t *c, lset_t policy) -{ - const struct dh_desc *ret = NULL; - - if ((policy & POLICY_PFS) && - c->alg_info_esp && c->alg_info_esp->esp_pfsgroup) - { - ret = ike_alg_get_dh_group(c->alg_info_esp->esp_pfsgroup); - } - return ret; -} - -/** - * Create an OAKLEY proposal based on alg_info and policy - */ -struct db_context *ike_alg_db_new(connection_t *c, lset_t policy) -{ - struct alg_info_ike *ai = c->alg_info_ike; - struct db_context *db_ctx = NULL; - struct ike_info *ike_info; - u_int ealg, halg, modp, eklen = 0; - int i; - - bool is_xauth_server = (policy & POLICY_XAUTH_SERVER) != LEMPTY; - - if (!ai) - { - whack_log(RC_LOG_SERIOUS, "no IKE algorithms " - "for this connection " - "(check ike algorithm string)"); - goto fail; - } - policy &= POLICY_ID_AUTH_MASK; - db_ctx = db_prop_new(PROTO_ISAKMP, 8, 8 * 5); - - /* for each group */ - ALG_INFO_IKE_FOREACH(ai, ike_info, i) - { - ealg = ike_info->ike_ealg; - halg = ike_info->ike_halg; - modp = ike_info->ike_modp; - eklen= ike_info->ike_eklen; - - if (!ike_alg_get_crypter(ealg)) - { - plog("ike alg: crypter %s not present", - enum_show(&oakley_enc_names, ealg)); - continue; - } - if (!ike_alg_get_hasher(halg)) - { - plog("ike alg: hasher %s not present", - enum_show(&oakley_hash_names, halg)); - continue; - } - if (!ike_alg_get_dh_group(modp)) - { - plog("ike alg: dh group %s not present", - enum_show(&oakley_group_names, modp)); - continue; - } - - if (policy & POLICY_PUBKEY) - { - int auth_method = 0, key_size = 0; - key_type_t key_type = KEY_ANY; - - if (c->spd.this.cert) - { - certificate_t *certificate = c->spd.this.cert->cert; - public_key_t *key = certificate->get_public_key(certificate); - - if (key == NULL) - { - plog("ike alg: unable to retrieve my public key"); - continue; - } - key_type = key->get_type(key); - key_size = key->get_keysize(key); - key->destroy(key); - } - else - { - private_key_t *key = get_private_key(c); - - if (key == NULL) - { - plog("ike alg: unable to retrieve my private key"); - continue; - } - key_type = key->get_type(key); - key_size = key->get_keysize(key); - } - switch (key_type) - { - case KEY_RSA: - auth_method = OAKLEY_RSA_SIG; - break; - case KEY_ECDSA: - switch (key_size) - { - case 256: - auth_method = OAKLEY_ECDSA_256; - break; - case 384: - auth_method = OAKLEY_ECDSA_384; - break; - case 521: - auth_method = OAKLEY_ECDSA_521; - break; - default: - continue; - } - break; - default: - continue; - } - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, auth_method); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_PSK) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_XAUTH_RSASIG) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD - , is_xauth_server ? XAUTHRespRSA : XAUTHInitRSA); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_XAUTH_PSK) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD - , is_xauth_server ? XAUTHRespPreShared : XAUTHInitPreShared); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - } -fail: - return db_ctx; -} - -/** - * Print the name of an algorithm plus the name of the plugin that registered it - */ -static void print_alg(char *buf, int *len, enum_names *alg_names, int alg_type, - const char *plugin_name) -{ - char alg_name[BUF_LEN]; - int alg_name_len; - - alg_name_len = sprintf(alg_name, " %s[%s]", enum_name(alg_names, alg_type), - plugin_name); - if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE) - { - whack_log(RC_COMMENT, "%s", buf); - *len = sprintf(buf, " "); - } - sprintf(buf + *len, "%s", alg_name); - *len += alg_name_len; -} - -/** - * Show registered IKE algorithms - */ -void ike_alg_list(void) -{ - rng_quality_t quality; - enumerator_t *enumerator; - const char *plugin_name; - char buf[BUF_LEN]; - int len; - struct ike_alg *a; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered IKEv1 Algorithms:"); - whack_log(RC_COMMENT, " "); - - len = sprintf(buf, " encryption:"); - for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_enc_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " integrity: "); - for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_hash_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " dh-group: "); - for (a = ike_alg_base[IKE_ALG_DH_GROUP]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_group_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " random-gen:"); - enumerator = lib->crypto->create_rng_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &quality, &plugin_name)) - { - len += sprintf(buf + len, " %N[%s]", rng_quality_names, quality, - plugin_name); - } - enumerator->destroy(enumerator); - whack_log(RC_COMMENT, "%s", buf); -} - -/** - * Show IKE algorithms for this connection (result from ike= string) - * and newest SA - */ -void ike_alg_show_connection(connection_t *c, const char *instance) -{ - struct state *st = state_with_serialno(c->newest_isakmp_sa); - - if (st) - { - if (st->st_oakley.encrypt == OAKLEY_3DES_CBC) - { - whack_log(RC_COMMENT, - "\"%s\"%s: IKE proposal: %s/%s/%s", - c->name, instance, - enum_show(&oakley_enc_names, st->st_oakley.encrypt), - enum_show(&oakley_hash_names, st->st_oakley.hash), - enum_show(&oakley_group_names, st->st_oakley.group->algo_id) - ); - } - else - { - whack_log(RC_COMMENT, - "\"%s\"%s: IKE proposal: %s_%u/%s/%s", - c->name, instance, - enum_show(&oakley_enc_names, st->st_oakley.encrypt), - st->st_oakley.enckeylen, - enum_show(&oakley_hash_names, st->st_oakley.hash), - enum_show(&oakley_group_names, st->st_oakley.group->algo_id) - ); - } - } -} - -/** - * ML: make F_STRICT logic consider enc,hash/auth,modp algorithms - */ -bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group, - struct alg_info_ike *alg_info_ike) -{ - /* - * simple test to discard low key_len, will accept it only - * if specified in "esp" string - */ - bool ealg_insecure = (key_len < 128); - - if (ealg_insecure - || (alg_info_ike && alg_info_ike->alg_info_flags & ALG_INFO_F_STRICT)) - { - int i; - struct ike_info *ike_info; - - if (alg_info_ike) - { - ALG_INFO_IKE_FOREACH(alg_info_ike, ike_info, i) - { - if (ike_info->ike_ealg == ealg - && (ike_info->ike_eklen == 0 || key_len == 0 || ike_info->ike_eklen == key_len) - && ike_info->ike_halg == aalg - && ike_info->ike_modp == group) - { - if (ealg_insecure) - loglog(RC_LOG_SERIOUS, "You should NOT use insecure IKE algorithms (%s)!" - , enum_name(&oakley_enc_names, ealg)); - return TRUE; - } - } - } - plog("Oakley Transform [%s (%d), %s, %s] refused due to %s" - , enum_name(&oakley_enc_names, ealg), key_len - , enum_name(&oakley_hash_names, aalg) - , enum_name(&oakley_group_names, group) - , ealg_insecure ? - "insecure key_len and enc. alg. not listed in \"ike\" string" : "strict flag" - ); - return FALSE; - } - return TRUE; -} - diff --git a/src/pluto/ike_alg.h b/src/pluto/ike_alg.h deleted file mode 100644 index c3ce8bb38..000000000 --- a/src/pluto/ike_alg.h +++ /dev/null @@ -1,76 +0,0 @@ -/* IKE modular algorithm handling interface - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _IKE_ALG_H -#define _IKE_ALG_H - -#include - -#include "connections.h" - -struct ike_alg { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; -}; - -struct encrypt_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t enc_blocksize; - u_int keydeflen; - u_int keymaxlen; - u_int keyminlen; -}; - -struct hash_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t hash_digest_size; -}; - -struct dh_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t ke_size; -}; - -#define IKE_ALG_ENCRYPT 0 -#define IKE_ALG_HASH 1 -#define IKE_ALG_DH_GROUP 2 -#define IKE_ALG_MAX IKE_ALG_DH_GROUP - -extern int ike_alg_add(struct ike_alg *a, const char *plugin_name); -extern struct hash_desc *ike_alg_get_hasher(u_int alg); -extern struct encrypt_desc *ike_alg_get_crypter(u_int alg); -extern struct dh_desc *ike_alg_get_dh_group(u_int alg); -extern const struct dh_desc* ike_alg_pfsgroup(struct connection *c, lset_t policy); -extern struct db_context * ike_alg_db_new(struct connection *c, lset_t policy); -extern void ike_alg_list(void); -extern void ike_alg_show_connection(struct connection *c, const char *instance); -extern bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group - , struct alg_info_ike *alg_info_ike); -extern int ike_alg_init(void); - -#endif /* _IKE_ALG_H */ diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c deleted file mode 100644 index 3e7adcc40..000000000 --- a/src/pluto/ipsec_doi.c +++ /dev/null @@ -1,5921 +0,0 @@ -/* IPsec DOI and Oakley resolution routines - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* missing from on old systems */ -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "state.h" -#include "x509.h" -#include "ac.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "smartcard.h" -#include "connections.h" -#include "keys.h" -#include "packet.h" -#include "demux.h" /* needs packet.h */ -#include "adns.h" /* needs */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "kernel.h" -#include "log.h" -#include "cookie.h" -#include "server.h" -#include "spdb.h" -#include "timer.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "whack.h" -#include "fetch.h" -#include "pkcs7.h" -#include "crypto.h" -#include "vendor.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "kernel_alg.h" -#include "nat_traversal.h" -#include "virtual.h" - -/* - * are we sending Pluto's Vendor ID? - */ -#ifdef VENDORID -#define SEND_PLUTO_VID 1 -#else /* !VENDORID */ -#define SEND_PLUTO_VID 0 -#endif /* !VENDORID */ - -/* - * are we sending an XAUTH VID? - */ -#ifdef XAUTH_VID -#define SEND_XAUTH_VID 1 -#else /* !XAUTH_VID */ -#define SEND_XAUTH_VID 0 -#endif /* !XAUTH_VID */ - -/* - * are we sending a Cisco Unity VID? - */ -#ifdef CISCO_QUIRKS -#define SEND_CISCO_UNITY_VID 1 -#else /* !CISCO_QUIRKS */ -#define SEND_CISCO_UNITY_VID 0 -#endif /* !CISCO_QUIRKS */ - -/* MAGIC: perform f, a function that returns notification_t - * and return from the ENCLOSING stf_status returning function if it fails. - */ -#define RETURN_STF_FAILURE(f) \ - { int r = (f); if (r != ISAKMP_NOTHING_WRONG) return STF_FAIL + r; } - -/* The endpoint(s) for which an SA is getting installed, so keying material - * can be properly wiped. - */ -enum endpoint { - EP_LOCAL = 1, - EP_REMOTE = 1 << 1, -}; - -/* create output HDR as replica of input HDR */ -void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np) -{ - struct isakmp_hdr r_hdr = md->hdr; /* mostly same as incoming header */ - - r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */ - if (enc) - { - r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION; - } - /* some day, we may have to set r_hdr.isa_version */ - r_hdr.isa_np = np; - if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) - { - impossible(); /* surely must have room and be well-formed */ - } -} - -/* Compute DH shared secret from our local secret and the peer's public value. - * We make the leap that the length should be that of the group - * (see quoted passage at start of ACCEPT_KE). - */ -static void compute_dh_shared(struct state *st, const chunk_t g) -{ - passert(st->st_dh); - st->st_dh->set_other_public_value(st->st_dh, g); - st->st_dh->get_shared_secret(st->st_dh, &st->st_shared); - DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared); -} - -/* if we haven't already done so, compute a local DH secret (st->st_sec) and - * the corresponding public value (g). This is emitted as a KE payload. - */ -static bool build_and_ship_KE(struct state *st, chunk_t *g, - const struct dh_desc *group, - pb_stream *outs, u_int8_t np) -{ - if (st->st_dh == NULL) - { - st->st_dh = lib->crypto->create_dh(lib->crypto, group->algo_id); - if (st->st_dh == NULL) - { - plog("Diffie Hellman group %N is not available", - diffie_hellman_group_names, group->algo_id); - return FALSE; - } - } - st->st_dh->get_my_public_value(st->st_dh, g); - DBG(DBG_CRYPT, - DBG_dump_chunk("Public DH value sent:\n", *g) - ) - return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value"); -} - -/* accept_ke - * - * Check and accept DH public value (Gi or Gr) from peer's message. - * According to RFC2409 "The Internet key exchange (IKE)" 5: - * The Diffie-Hellman public value passed in a KE payload, in either - * a phase 1 or phase 2 exchange, MUST be the length of the negotiated - * Diffie-Hellman group enforced, if necessary, by pre-pending the - * value with zeros. - */ -static notification_t accept_KE(chunk_t *dest, const char *val_name, - const struct dh_desc *gr, - pb_stream *pbs) -{ - if (pbs_left(pbs) != gr->ke_size) - { - loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required" - , (unsigned) pbs_left(pbs), gr->ke_size); - /* XXX Could send notification back */ - return ISAKMP_INVALID_KEY_INFORMATION; - } - free(dest->ptr); - *dest = chunk_create(pbs->cur, pbs_left(pbs)); - *dest = chunk_clone(*dest); - DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest); - return ISAKMP_NOTHING_WRONG; -} - -/* accept_PFS_KE - * - * Check and accept optional Quick Mode KE payload for PFS. - * Extends ACCEPT_PFS to check whether KE is allowed or required. - */ -static notification_t accept_PFS_KE(struct msg_digest *md, chunk_t *dest, - const char *val_name, const char *msg_name) -{ - struct state *st = md->st; - struct payload_digest *const ke_pd = md->chain[ISAKMP_NEXT_KE]; - - if (ke_pd == NULL) - { - if (st->st_pfs_group != NULL) - { - loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; - } - } - else - { - if (st->st_pfs_group == NULL) - { - loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA" - , msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; - } - if (ke_pd->next != NULL) - { - loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; /* ??? */ - } - return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs); - } - return ISAKMP_NOTHING_WRONG; -} - -static bool build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np, - const char *name) -{ - rng_t *rng; - - free(n->ptr); - *n = chunk_create(malloc(DEFAULT_NONCE_SIZE), DEFAULT_NONCE_SIZE); - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->get_bytes(rng, DEFAULT_NONCE_SIZE, n->ptr); - rng->destroy(rng); - return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name); -} - -static linked_list_t* collect_rw_ca_candidates(struct msg_digest *md) -{ - linked_list_t *list = linked_list_create(); - connection_t *d; - - d = find_host_connection(&md->iface->addr, pluto_port, (ip_address*)NULL, - md->sender_port, LEMPTY); - - for (; d != NULL; d = d->hp_next) - { - /* must be a road warrior connection */ - if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO) && - d->spd.that.ca) - { - enumerator_t *enumerator; - identification_t *ca; - bool new_entry = TRUE; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &ca)) - { - if (ca->equals(ca, d->spd.that.ca)) - { - new_entry = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (new_entry) - { - list->insert_last(list, d->spd.that.ca->clone(d->spd.that.ca)); - } - } - } - return list; -} - -static bool build_and_ship_CR(u_int8_t type, chunk_t ca, pb_stream *outs, - u_int8_t np) -{ - pb_stream cr_pbs; - struct isakmp_cr cr_hd; - cr_hd.isacr_np = np; - cr_hd.isacr_type = type; - - /* build CR header */ - if (!out_struct(&cr_hd, &isakmp_ipsec_cert_req_desc, outs, &cr_pbs)) - { - return FALSE; - } - if (ca.ptr != NULL) - { - /* build CR body containing the distinguished name of the CA */ - if (!out_chunk(ca, &cr_pbs, "CA")) - return FALSE; - } - close_output_pbs(&cr_pbs); - return TRUE; -} - -/* Send a notification to the peer. We could decide - * whether to send the notification, based on the type and the - * destination, if we care to. - */ -static void send_notification(struct state *sndst, u_int16_t type, - struct state *encst, msgid_t msgid, - u_char *icookie, u_char *rcookie, - u_char *spi, size_t spisize, u_char protoid) -{ - u_char buffer[1024]; - pb_stream pbs, r_hdr_pbs; - u_char *r_hashval = NULL; /* where in reply to jam hash value */ - u_char *r_hash_start = NULL; /* start of what is to be hashed */ - - passert((sndst) && (sndst->st_connection)); - - plog("sending %snotification %s to %s:%u" - , encst ? "encrypted " : "" - , enum_name(¬ification_names, type) - , ip_str(&sndst->st_connection->spd.that.host_addr) - , (unsigned)sndst->st_connection->spd.that.host_port); - - memset(buffer, 0, sizeof(buffer)); - init_pbs(&pbs, buffer, sizeof(buffer), "ISAKMP notify"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = encst ? ISAKMP_FLAG_ENCRYPTION : 0; - if (icookie) - { - memcpy(hdr.isa_icookie, icookie, COOKIE_SIZE); - } - if (rcookie) - { - memcpy(hdr.isa_rcookie, rcookie, COOKIE_SIZE); - } - if (!out_struct(&hdr, &isakmp_hdr_desc, &pbs, &r_hdr_pbs)) - { - impossible(); - } - } - - /* HASH -- value to be filled later */ - if (encst) - { - pb_stream hash_pbs; - if (!out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) - { - impossible(); - } - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero( - encst->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) - { - impossible(); - } - close_output_pbs(&hash_pbs); - r_hash_start = r_hdr_pbs.cur; /* hash from after HASH */ - } - - /* Notification Payload */ - { - pb_stream not_pbs; - struct isakmp_notification isan; - - isan.isan_doi = ISAKMP_DOI_IPSEC; - isan.isan_np = ISAKMP_NEXT_NONE; - isan.isan_type = type; - isan.isan_spisize = spisize; - isan.isan_protoid = protoid; - - if (!out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs, ¬_pbs) - || !out_raw(spi, spisize, ¬_pbs, "spi")) - { - impossible(); - } - close_output_pbs(¬_pbs); - } - - /* calculate hash value and patch into Hash Payload */ - if (encst) - { - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(encst->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, encst->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - prf->destroy(prf); - } - - /* Encrypt message (preserve st_iv and st_new_iv) */ - if (encst) - { - u_char old_iv[MAX_DIGEST_LEN]; - u_char new_iv[MAX_DIGEST_LEN]; - - u_int old_iv_len = encst->st_iv_len; - u_int new_iv_len = encst->st_new_iv_len; - - if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) - { - impossible(); - } - memcpy(old_iv, encst->st_iv, old_iv_len); - memcpy(new_iv, encst->st_new_iv, new_iv_len); - - if (!IS_ISAKMP_SA_ESTABLISHED(encst->st_state)) - { - memcpy(encst->st_ph1_iv, encst->st_new_iv, encst->st_new_iv_len); - encst->st_ph1_iv_len = encst->st_new_iv_len; - } - init_phase2_iv(encst, &msgid); - if (!encrypt_message(&r_hdr_pbs, encst)) - { - impossible(); - } - - /* restore preserved st_iv and st_new_iv */ - memcpy(encst->st_iv, old_iv, old_iv_len); - memcpy(encst->st_new_iv, new_iv, new_iv_len); - encst->st_iv_len = old_iv_len; - encst->st_new_iv_len = new_iv_len; - } - else - { - close_output_pbs(&r_hdr_pbs); - } - - /* Send packet (preserve st_tpacket) */ - { - chunk_t saved_tpacket = sndst->st_tpacket; - - sndst->st_tpacket = chunk_create(pbs.start, pbs_offset(&pbs)); - send_packet(sndst, "ISAKMP notify"); - sndst->st_tpacket = saved_tpacket; - } -} - -void send_notification_from_state(struct state *st, enum state_kind state, - u_int16_t type) -{ - struct state *p1st; - - passert(st); - - if (state == STATE_UNDEFINED) - state = st->st_state; - - if (IS_QUICK(state)) - { - p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - if ((p1st == NULL) || (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state))) - { - loglog(RC_LOG_SERIOUS, - "no Phase1 state for Quick mode notification"); - return; - } - send_notification(st, type, p1st, generate_msgid(p1st), - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } - else if (IS_ISAKMP_ENCRYPTED(state) && st->st_enc_key.ptr != NULL) - { - send_notification(st, type, st, generate_msgid(st), - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } - else - { - /* no ISAKMP SA established - don't encrypt notification */ - send_notification(st, type, NULL, 0, - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } -} - -void send_notification_from_md(struct msg_digest *md, u_int16_t type) -{ - /** - * Create a dummy state to be able to use send_packet in - * send_notification - * - * we need to set: - * st_connection->that.host_addr - * st_connection->that.host_port - * st_connection->interface - */ - struct state st; - connection_t cnx; - - passert(md); - - memset(&st, 0, sizeof(st)); - memset(&cnx, 0, sizeof(cnx)); - st.st_connection = &cnx; - cnx.spd.that.host_addr = md->sender; - cnx.spd.that.host_port = md->sender_port; - cnx.interface = md->iface; - - send_notification(&st, type, NULL, 0, - md->hdr.isa_icookie, md->hdr.isa_rcookie, NULL, 0, PROTO_ISAKMP); -} - -/* Send a Delete Notification to announce deletion of ISAKMP SA or - * inbound IPSEC SAs. Does nothing if no such SAs are being deleted. - * Delete Notifications cannot announce deletion of outbound IPSEC/ISAKMP SAs. - */ -void send_delete(struct state *st) -{ - pb_stream reply_pbs; - pb_stream r_hdr_pbs; - msgid_t msgid; - u_char buffer[8192]; - struct state *p1st; - ip_said said[EM_MAXRELSPIS]; - ip_said *ns = said; - u_char - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - bool isakmp_sa = FALSE; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - if (p1st == NULL) - { - DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete")); - return; - } - - if (st->st_ah.present) - { - ns->spi = st->st_ah.our_spi; - ns->dst = st->st_connection->spd.this.host_addr; - ns->proto = PROTO_IPSEC_AH; - ns++; - } - if (st->st_esp.present) - { - ns->spi = st->st_esp.our_spi; - ns->dst = st->st_connection->spd.this.host_addr; - ns->proto = PROTO_IPSEC_ESP; - ns++; - } - - passert(ns != said); /* there must be some SAs to delete */ - } - else if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - p1st = st; - isakmp_sa = TRUE; - } - else - { - return; /* nothing to do */ - } - - msgid = generate_msgid(p1st); - - zero(buffer); - init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, p1st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, p1st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_pbs, &r_hdr_pbs)) - impossible(); - } - - /* HASH -- value to be filled later */ - { - pb_stream hash_pbs; - - if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) - { - impossible(); - } - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero(p1st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH(1)")) - { - impossible(); - } - close_output_pbs(&hash_pbs); - r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ - } - - /* Delete Payloads */ - if (isakmp_sa) - { - pb_stream del_pbs; - struct isakmp_delete isad; - u_char isakmp_spi[2*COOKIE_SIZE]; - - isad.isad_doi = ISAKMP_DOI_IPSEC; - isad.isad_np = ISAKMP_NEXT_NONE; - isad.isad_spisize = (2 * COOKIE_SIZE); - isad.isad_protoid = PROTO_ISAKMP; - isad.isad_nospi = 1; - - memcpy(isakmp_spi, st->st_icookie, COOKIE_SIZE); - memcpy(isakmp_spi+COOKIE_SIZE, st->st_rcookie, COOKIE_SIZE); - - if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) - || !out_raw(&isakmp_spi, (2*COOKIE_SIZE), &del_pbs, "delete payload")) - { - impossible(); - } - close_output_pbs(&del_pbs); - } - else - { - while (ns != said) - { - - pb_stream del_pbs; - struct isakmp_delete isad; - - ns--; - isad.isad_doi = ISAKMP_DOI_IPSEC; - isad.isad_np = ns == said? ISAKMP_NEXT_NONE : ISAKMP_NEXT_D; - isad.isad_spisize = sizeof(ipsec_spi_t); - isad.isad_protoid = ns->proto; - - isad.isad_nospi = 1; - if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) - || !out_raw(&ns->spi, sizeof(ipsec_spi_t), &del_pbs, "delete payload")) - { - impossible(); - } - close_output_pbs(&del_pbs); - } - } - - /* calculate hash value and patch into Hash Payload */ - { - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(p1st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, p1st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH(1) computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - - prf->destroy(prf); - } - - /* Do a dance to avoid needing a new state object. - * We use the Phase 1 State. This is the one with right - * IV, for one thing. - * The tricky bits are: - * - we need to preserve (save/restore) st_iv (but not st_iv_new) - * - we need to preserve (save/restore) st_tpacket. - */ - { - u_char old_iv[MAX_DIGEST_LEN]; - chunk_t saved_tpacket = p1st->st_tpacket; - - memcpy(old_iv, p1st->st_iv, p1st->st_iv_len); - init_phase2_iv(p1st, &msgid); - - if (!encrypt_message(&r_hdr_pbs, p1st)) - { - impossible(); - } - p1st->st_tpacket = chunk_create(reply_pbs.start, pbs_offset(&reply_pbs)); - send_packet(p1st, "delete notify"); - p1st->st_tpacket = saved_tpacket; - - /* get back old IV for this state */ - memcpy(p1st->st_iv, old_iv, p1st->st_iv_len); - } -} - -void accept_delete(struct state *st, struct msg_digest *md, - struct payload_digest *p) -{ - struct isakmp_delete *d = &(p->payload.delete); - identification_t *this_id = NULL, *that_id = NULL; - ip_address peer_addr; - size_t sizespi; - int i; - - if (!md->encrypted) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: not encrypted"); - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - /* can't happen (if msg is encrypt), but just to be sure */ - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA not established"); - return; - } - - if (d->isad_nospi == 0) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI"); - return; - } - - switch (d->isad_protoid) - { - case PROTO_ISAKMP: - sizespi = 2 * COOKIE_SIZE; - break; - case PROTO_IPSEC_AH: - case PROTO_IPSEC_ESP: - sizespi = sizeof(ipsec_spi_t); - break; - case PROTO_IPCOMP: - /* nothing interesting to delete */ - return; - default: - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: unknown Protocol ID (%s)" - , enum_show(&protocol_names, d->isad_protoid)); - return; - } - - if (d->isad_spisize != sizespi) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: bad SPI size (%d) for %s" - , d->isad_spisize, enum_show(&protocol_names, d->isad_protoid)); - return; - } - - if (pbs_left(&p->pbs) != d->isad_nospi * sizespi) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: invalid payload size"); - return; - } - - if (d->isad_protoid == PROTO_ISAKMP) - { - struct end *this = &st->st_connection->spd.this; - struct end *that = &st->st_connection->spd.that; - this_id = this->id->clone(this->id); - that_id = that->id->clone(that->id); - peer_addr = st->st_connection->spd.that.host_addr; - } - - for (i = 0; i < d->isad_nospi; i++) - { - u_char *spi = p->pbs.cur + (i * sizespi); - - if (d->isad_protoid == PROTO_ISAKMP) - { - /** - * ISAKMP - */ - struct state *dst = find_state(spi /*iCookie*/ - , spi+COOKIE_SIZE /*rCookie*/ - , &peer_addr - , MAINMODE_MSGID); - - if (dst == NULL) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA not found (maybe expired)"); - } - else if (! this_id->equals(this_id, dst->st_connection->spd.this.id) || - ! that_id->equals(that_id, dst->st_connection->spd.that.id)) - { - /* we've not authenticated the relevant identities */ - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA used to convey Delete has different IDs from ISAKMP SA it deletes"); - } - else - { - connection_t *oldc; - - oldc = cur_connection; - set_cur_connection(dst->st_connection); - - if (nat_traversal_enabled) - { - nat_traversal_change_port_lookup(md, dst); - } - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "deleting ISAKMP State #%lu", dst->st_serialno); - delete_state(dst); - set_cur_connection(oldc); - } - } - else - { - /** - * IPSEC (ESP/AH) - */ - bool bogus; - struct state *dst = find_phase2_state_to_delete(st - , d->isad_protoid - , *(ipsec_spi_t *)spi /* network order */ - , &bogus); - - if (dst == NULL) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: %s SA(0x%08lx) not found (%s)" - , enum_show(&protocol_names, d->isad_protoid) - , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) - , bogus ? "our SPI - bogus implementation" : "maybe expired"); - } - else - { - connection_t *rc = dst->st_connection; - connection_t *oldc; - - oldc = cur_connection; - set_cur_connection(rc); - - if (nat_traversal_enabled) - { - nat_traversal_change_port_lookup(md, dst); - } - if (rc->newest_ipsec_sa == dst->st_serialno - && (rc->policy & POLICY_UP)) - { - /* Last IPSec SA for a permanent connection that we - * have initiated. Replace it in a few seconds. - * - * Useful if the other peer is rebooting. - */ -#define DELETE_SA_DELAY EVENT_RETRANSMIT_DELAY_0 - if (dst->st_event != NULL - && dst->st_event->ev_type == EVENT_SA_REPLACE - && dst->st_event->ev_time <= DELETE_SA_DELAY + now()) - { - /* Patch from Angus Lees to ignore retransmited - * Delete SA. - */ - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "already replacing IPSEC State #%lu in %d seconds" - , dst->st_serialno, (int)(dst->st_event->ev_time - now())); - } - else - { - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "replace IPSEC State #%lu in %d seconds" - , dst->st_serialno, DELETE_SA_DELAY); - dst->st_margin = DELETE_SA_DELAY; - delete_event(dst); - event_schedule(EVENT_SA_REPLACE, DELETE_SA_DELAY, dst); - } - } - else - { - loglog(RC_LOG_SERIOUS, "received Delete SA(0x%08lx) payload: " - "deleting IPSEC State #%lu" - , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) - , dst->st_serialno); - delete_state(dst); - } - - /* reset connection */ - set_cur_connection(oldc); - } - } - } - - if (d->isad_protoid == PROTO_ISAKMP) - { - this_id->destroy(this_id); - that_id->destroy(that_id); - } -} - -/* The whole message must be a multiple of 4 octets. - * I'm not sure where this is spelled out, but look at - * rfc2408 3.6 Transform Payload. - * Note: it talks about 4 BYTE boundaries! - */ -void close_message(pb_stream *pbs) -{ - size_t padding = pad_up(pbs_offset(pbs), 4); - - if (padding != 0) - { - (void) out_zero(padding, pbs, "message padding"); - } - close_output_pbs(pbs); -} - -/* Initiate an Oakley Main Mode exchange. - * --> HDR;SA - * Note: this is not called from demux.c - */ -static stf_status -main_outI1(int whack_sock, connection_t *c, struct state *predecessor - , lset_t policy, unsigned long try) -{ - struct state *st = new_state(); - pb_stream reply; /* not actually a reply, but you know what I mean */ - pb_stream rbody; - int vids_to_send = 0; - - /* set up new state */ - st->st_connection = c; - set_cur_state(st); /* we must reset before exit */ - st->st_policy = policy & ~POLICY_IPSEC_MASK; - st->st_whack_sock = whack_sock; - st->st_try = try; - st->st_state = STATE_MAIN_I1; - - /* determine how many Vendor ID payloads we will be sending */ - if (SEND_PLUTO_VID) - { - vids_to_send++; - } - if (SEND_CISCO_UNITY_VID) - { - vids_to_send++; - } - if (c->spd.this.cert && - c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) - { - vids_to_send++; - } - if (SEND_XAUTH_VID) - { - vids_to_send++; - } - - /* always send DPD Vendor ID */ - vids_to_send++; - - if (nat_traversal_enabled) - { - vids_to_send++; - } - - get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr); - - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - if (HAS_IPSEC_POLICY(policy)) - { - add_pending(dup_any(whack_sock), st, c, policy, 1 - , predecessor == NULL? SOS_NOBODY : predecessor->st_serialno); - } - if (predecessor == NULL) - { - plog("initiating Main Mode"); - } - else - { - plog("initiating Main Mode to replace #%lu", predecessor->st_serialno); - } - - /* set up reply */ - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - /* HDR out */ - { - struct isakmp_hdr hdr; - - zero(&hdr); /* default to 0 */ - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_SA; - hdr.isa_xchg = ISAKMP_XCHG_IDPROT; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - /* R-cookie, flags and MessageID are left zero */ - - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* SA out */ - { - u_char *sa_start = rbody.cur; - - if (!out_sa(&rbody, &oakley_sadb, st, TRUE - , vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* save initiator SA for later HASH */ - passert(st->st_p1isa.ptr == NULL); /* no leak! (MUST be first time) */ - st->st_p1isa = chunk_create(sa_start, rbody.cur - sa_start); - st->st_p1isa = chunk_clone(st->st_p1isa); - } - - /* if enabled send Pluto Vendor ID */ - if (SEND_PLUTO_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_STRONGSWAN)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* if enabled send Cisco Unity Vendor ID */ - if (SEND_CISCO_UNITY_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_CISCO_UNITY)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - /* if we have an OpenPGP certificate we assume an - * OpenPGP peer and have to send the Vendor ID - */ - if (c->spd.this.cert && - c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_OPENPGP)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do eXtended AUTHentication to the peer */ - if (SEND_XAUTH_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_MISC_XAUTH)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do Dead Peer Detection to the peer */ - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_MISC_DPD)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - if (nat_traversal_enabled) - { - /* Add supported NAT-Traversal VID */ - if (!nat_traversal_add_vid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - close_message(&rbody); - close_output_pbs(&reply); - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* Transmit */ - - send_packet(st, "main_outI1"); - - /* Set up a retransmission event, half a minute henceforth */ - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - - if (predecessor != NULL) - { - update_pending(predecessor, st); - whack_log(RC_NEW_STATE + STATE_MAIN_I1 - , "%s: initiate, replacing #%lu" - , enum_name(&state_names, st->st_state) - , predecessor->st_serialno); - } - else - { - whack_log(RC_NEW_STATE + STATE_MAIN_I1 - , "%s: initiate", enum_name(&state_names, st->st_state)); - } - reset_cur_state(); - return STF_OK; -} - -void ipsecdoi_initiate(int whack_sock, connection_t *c, lset_t policy, - unsigned long try, so_serial_t replacing) -{ - /* If there's already an ISAKMP SA established, use that and - * go directly to Quick Mode. We are even willing to use one - * that is still being negotiated, but only if we are the Initiator - * (thus we can be sure that the IDs are not going to change; - * other issues around intent might matter). - * Note: there is no way to initiate with a Road Warrior. - */ - struct state *st = find_phase1_state(c - , ISAKMP_SA_ESTABLISHED_STATES | PHASE1_INITIATOR_STATES); - - if (st == NULL) - { - (void) main_outI1(whack_sock, c, NULL, policy, try); - } - else if (HAS_IPSEC_POLICY(policy)) - { - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - /* leave our Phase 2 negotiation pending */ - add_pending(whack_sock, st, c, policy, try, replacing); - } - else - { - /* ??? we assume that peer_nexthop_sin isn't important: - * we already have it from when we negotiated the ISAKMP SA! - * It isn't clear what to do with the error return. - */ - (void) quick_outI1(whack_sock, st, c, policy, try, replacing); - } - } - else - { - close_any(whack_sock); - } -} - -/* Replace SA with a fresh one that is similar - * - * Shares some logic with ipsecdoi_initiate, but not the same! - * - we must not reuse the ISAKMP SA if we are trying to replace it! - * - if trying to replace IPSEC SA, use ipsecdoi_initiate to build - * ISAKMP SA if needed. - * - duplicate whack fd, if live. - * Does not delete the old state -- someone else will do that. - */ -void ipsecdoi_replace(struct state *st, unsigned long try) -{ - int whack_sock = dup_any(st->st_whack_sock); - lset_t policy = st->st_policy; - - if (IS_PHASE1(st->st_state)) - { - passert(!HAS_IPSEC_POLICY(policy)); - (void) main_outI1(whack_sock, st->st_connection, st, policy, try); - } - else - { - /* Add features of actual old state to policy. This ensures - * that rekeying doesn't downgrade security. I admit that - * this doesn't capture everything. - */ - if (st->st_pfs_group != NULL) - policy |= POLICY_PFS; - if (st->st_ah.present) - { - policy |= POLICY_AUTHENTICATE; - if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - if (st->st_esp.present && st->st_esp.attrs.transid != ESP_NULL) - { - policy |= POLICY_ENCRYPT; - if (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - if (st->st_ipcomp.present) - { - policy |= POLICY_COMPRESS; - if (st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - passert(HAS_IPSEC_POLICY(policy)); - ipsecdoi_initiate(whack_sock, st->st_connection, policy, try - , st->st_serialno); - } -} - -/* SKEYID for preshared keys. - * See draft-ietf-ipsec-ike-01.txt 4.1 - */ -static bool skeyid_preshared(struct state *st) -{ - const chunk_t *pss = get_preshared_secret(st->st_connection); - - if (pss == NULL) - { - loglog(RC_LOG_SERIOUS, "preshared secret disappeared!"); - return FALSE; - } - else - { - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - if (prf == NULL) - { - loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid", - pseudo_random_function_names, prf_alg); - return FALSE; - } - free(st->st_skeyid.ptr); - prf->set_key(prf, *pss); - prf->allocate_bytes(prf, st->st_ni, NULL); - prf->allocate_bytes(prf, st->st_nr, &st->st_skeyid); - prf->destroy(prf); - return TRUE; - } -} - -static bool skeyid_digisig(struct state *st) -{ - chunk_t nir; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - if (prf == NULL) - { - loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid", - pseudo_random_function_names, prf_alg); - return FALSE; - } - free(st->st_skeyid.ptr); - nir = chunk_cat("cc", st->st_ni, st->st_nr); - prf->set_key(prf, nir); - prf->allocate_bytes(prf, st->st_shared, &st->st_skeyid); - prf->destroy(prf); - free(nir.ptr); - return TRUE; -} - -/* Generate the SKEYID_* and new IV - * See draft-ietf-ipsec-ike-01.txt 4.1 - */ -static bool generate_skeyids_iv(struct state *st) -{ - /* Generate the SKEYID */ - switch (st->st_oakley.auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - if (!skeyid_preshared(st)) - { - return FALSE; - } - break; - - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - if (!skeyid_digisig(st)) - { - return FALSE; - } - break; - - case OAKLEY_DSS_SIG: - /* XXX */ - - case OAKLEY_RSA_ENC: - case OAKLEY_RSA_ENC_REV: - case OAKLEY_ELGAMAL_ENC: - case OAKLEY_ELGAMAL_ENC_REV: - /* XXX */ - - default: - bad_case(st->st_oakley.auth); - } - - /* generate SKEYID_* from SKEYID */ - { - chunk_t seed_skeyid_d = chunk_from_chars(0x00); - chunk_t seed_skeyid_a = chunk_from_chars(0x01); - chunk_t seed_skeyid_e = chunk_from_chars(0x02); - chunk_t icookie = { st->st_icookie, COOKIE_SIZE }; - chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid); - - /* SKEYID_D */ - free(st->st_skeyid_d.ptr); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_d, &st->st_skeyid_d); - - /* SKEYID_A */ - free(st->st_skeyid_a.ptr); - prf->allocate_bytes(prf, st->st_skeyid_d, NULL); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_a, &st->st_skeyid_a); - - /* SKEYID_E */ - free(st->st_skeyid_e.ptr); - prf->allocate_bytes(prf, st->st_skeyid_a, NULL); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_e, &st->st_skeyid_e); - - prf->destroy(prf); - } - - /* generate IV */ - { - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = oakley_to_hash_algorithm(st->st_oakley.hash); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - st->st_new_iv_len = hasher->get_hash_size(hasher); - passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); - - DBG(DBG_CRYPT, - DBG_dump_chunk("DH_i:", st->st_gi); - DBG_dump_chunk("DH_r:", st->st_gr); - ); - - hasher->get_hash(hasher, st->st_gi, NULL); - hasher->get_hash(hasher, st->st_gr, st->st_new_iv); - hasher->destroy(hasher); - } - - /* Oakley Keying Material - * Derived from Skeyid_e: if it is not big enough, generate more - * using the PRF. - * See RFC 2409 "IKE" Appendix B - */ - { - size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE; - - /* free any existing key */ - free(st->st_enc_key.ptr); - - if (keysize > st->st_skeyid_e.len) - { - u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN]; - chunk_t seed = chunk_from_chars(0x00); - size_t prf_block_size, i; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_e); - prf_block_size = prf->get_block_size(prf); - - for (i = 0;;) - { - prf->get_bytes(prf, seed, &keytemp[i]); - i += prf_block_size; - if (i >= keysize) - { - break; - } - seed = chunk_create(&keytemp[i-prf_block_size], prf_block_size); - } - prf->destroy(prf); - st->st_enc_key = chunk_create(keytemp, keysize); - } - else - { - st->st_enc_key = chunk_create(st->st_skeyid_e.ptr, keysize); - } - st->st_enc_key = chunk_clone(st->st_enc_key); - } - - DBG(DBG_CRYPT, - DBG_dump_chunk("Skeyid: ", st->st_skeyid); - DBG_dump_chunk("Skeyid_d:", st->st_skeyid_d); - DBG_dump_chunk("Skeyid_a:", st->st_skeyid_a); - DBG_dump_chunk("Skeyid_e:", st->st_skeyid_e); - DBG_dump_chunk("enc key:", st->st_enc_key); - DBG_dump("IV:", st->st_new_iv, st->st_new_iv_len)); - return TRUE; -} - -/* Generate HASH_I or HASH_R for ISAKMP Phase I. - * This will *not* generate other hash payloads (eg. Phase II or Quick Mode, - * New Group Mode, or ISAKMP Informational Exchanges). - * If the hashi argument is TRUE, generate HASH_I; if FALSE generate HASH_R. - * If hashus argument is TRUE, we're generating a hash for our end. - * See RFC2409 IKE 5. - */ - static void main_mode_hash(struct state *st, chunk_t *hash, bool hashi, - const pb_stream *idpl) -{ - chunk_t icookie = { st->st_icookie, COOKIE_SIZE }; - chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE }; - chunk_t sa_body = { st->st_p1isa.ptr + sizeof(struct isakmp_generic), - st->st_p1isa.len - sizeof(struct isakmp_generic) }; - chunk_t id_body = { idpl->start + sizeof(struct isakmp_generic), - pbs_offset(idpl) - sizeof(struct isakmp_generic) }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - switch (st->st_oakley.auth) - { - case OAKLEY_ECDSA_256: - prf_alg = PRF_HMAC_SHA2_256; - break; - case OAKLEY_ECDSA_384: - prf_alg = PRF_HMAC_SHA2_384; - break; - case OAKLEY_ECDSA_521: - prf_alg = PRF_HMAC_SHA2_512; - break; - default: - prf_alg = oakley_to_prf(st->st_oakley.hash); - } - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid); - - if (hashi) - { - prf->get_bytes(prf, st->st_gi, NULL); - prf->get_bytes(prf, st->st_gr, NULL); - prf->get_bytes(prf, icookie, NULL); - prf->get_bytes(prf, rcookie, NULL); - } - else - { - prf->get_bytes(prf, st->st_gr, NULL); - prf->get_bytes(prf, st->st_gi, NULL); - prf->get_bytes(prf, rcookie, NULL); - prf->get_bytes(prf, icookie, NULL); - } - - DBG(DBG_CRYPT, - DBG_log("hashing %u bytes of SA", sa_body.len) - ) - prf->get_bytes(prf, sa_body, NULL); - - /* Hash identification payload, without generic payload header. - * We used to reconstruct ID Payload for this purpose, but now - * we use the bytes as they appear on the wire to avoid - * "spelling problems". - */ - prf->get_bytes(prf, id_body, hash->ptr); - hash->len = prf->get_block_size(prf); - prf->destroy(prf); -} - -/* Create a public key signature of a hash. - * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2. - * Use PKCS#1 version 1.5 encryption of hash (called - * RSAES-PKCS1-V1_5) in PKCS#2. - */ -static size_t sign_hash(signature_scheme_t scheme, connection_t *c, - u_char sig_val[RSA_MAX_OCTETS], chunk_t hash) -{ - size_t sz = 0; - smartcard_t *sc = c->spd.this.sc; - - if (sc == NULL) /* no smartcard */ - { - chunk_t sig; - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - return 0; /* failure: no key to use */ - } - if (!private->sign(private, scheme, hash, &sig)) - { - return 0; - } - memcpy(sig_val, sig.ptr, sig.len); - sz = sig.len; - free(sig.ptr); - } - else if (sc->valid) /* if valid pin then sign hash on the smartcard */ - { - lock_certs_and_keys("sign_hash"); - if (!scx_establish_context(sc) || !scx_login(sc)) - { - scx_release_context(sc); - unlock_certs_and_keys("sign_hash"); - return 0; - } - - sz = scx_get_keylength(sc); - if (sz == 0) - { - plog("failed to get keylength from smartcard"); - scx_release_context(sc); - unlock_certs_and_keys("sign_hash"); - return 0; - } - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("signing hash with private key from smartcard (slot: %d, id: %s)" - , (int)sc->slot, sc->id) - ) - sz = scx_sign_hash(sc, hash.ptr, hash.len, sig_val, sz) ? sz : 0; - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - unlock_certs_and_keys("sign_hash"); - } - return sz; -} - -/* Check signature against all public keys we can find. - * If we need keys from DNS KEY records, and they haven't been fetched, - * return STF_SUSPEND to ask for asynch DNS lookup. - * - * Note: parameter keys_from_dns contains results of DNS lookup for key - * or is NULL indicating lookup not yet tried. - * - * take_a_crack is a helper function. Mostly forensic. - * If only we had coroutines. - */ -struct tac_state { - struct state *st; - chunk_t hash; - chunk_t sig; - int tried_cnt; /* number of keys tried */ -}; - -static bool take_a_crack(struct tac_state *s, pubkey_t *kr) -{ - public_key_t *pub_key = kr->public_key; - chunk_t keyid = chunk_empty; - signature_scheme_t scheme; - - s->tried_cnt++; - scheme = oakley_to_signature_scheme(s->st->st_oakley.auth); - pub_key->get_fingerprint(pub_key, KEYID_PUBKEY_INFO_SHA1, &keyid); - - if (pub_key->verify(pub_key, scheme, s->hash, s->sig)) - { - DBG(DBG_CRYPT | DBG_CONTROL, - DBG_log("%s check passed with keyid %#B", - enum_show(&oakley_auth_names, s->st->st_oakley.auth), &keyid) - ) - unreference_key(&s->st->st_peer_pubkey); - s->st->st_peer_pubkey = reference_key(kr); - return TRUE; - } - else - { - DBG(DBG_CRYPT, - DBG_log("%s check failed with keyid %#B", - enum_show(&oakley_auth_names, s->st->st_oakley.auth), &keyid) - ) - return FALSE; - } -} - -static stf_status check_signature(key_type_t key_type, identification_t* peer, - struct state *st, chunk_t hash, - const pb_stream *sig_pbs, -#ifdef USE_KEYRR - const pubkey_list_t *keys_from_dns, -#endif /* USE_KEYRR */ - const struct gw_info *gateways_from_dns) -{ - const connection_t *c = st->st_connection; - struct tac_state s; - - s.st = st; - s.hash = hash; - s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs)); - s.tried_cnt = 0; - - /* try all gateway records hung off c */ - if (c->policy & POLICY_OPPO) - { - struct gw_info *gw; - - for (gw = c->gw_info; gw != NULL; gw = gw->next) - { - /* only consider entries that have a key and are for our peer */ - if (gw->gw_key_present && - gw->gw_id->equals(gw->gw_id, c->spd.that.id) && - take_a_crack(&s, gw->key)) - { - return STF_OK; - } - } - } - - /* try all appropriate Public keys */ - { - pubkey_list_t *p, **pp; - - pp = &pubkeys; - - for (p = pubkeys; p != NULL; p = *pp) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - - if (type == key_type && peer->equals(peer, key->id)) - { - time_t now = time(NULL); - - /* check if found public key has expired */ - if (key->until_time != UNDEFINED_TIME && key->until_time < now) - { - loglog(RC_LOG_SERIOUS, - "cached public key has expired and has been deleted"); - *pp = free_public_keyentry(p); - continue; /* continue with next public key */ - } - if (take_a_crack(&s, key)) - { - return STF_OK; - } - } - pp = &p->next; - } - } - - /* if no key was found and that side of connection is - * key_from_DNS_on_demand then go search DNS for keys for peer. - */ - if (s.tried_cnt == 0 && c->spd.that.key_from_DNS_on_demand) - { - if (gateways_from_dns != NULL) - { - /* TXT keys */ - const struct gw_info *gwp; - - for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - if (gwp->gw_key_present && take_a_crack(&s, gwp->key)) - { - return STF_OK; - } - } - } -#ifdef USE_KEYRR - else if (keys_from_dns != NULL) - { - /* KEY keys */ - const pubkey_list_t *kr; - - for (kr = keys_from_dns; kr != NULL; kr = kr->next) - { - if (kr->key->alg == PUBKEY_ALG_RSA && take_a_crack(&s, kr->key)) - { - return STF_OK; - } - } - } -#endif /* USE_KEYRR */ - else - { - /* nothing yet: ask for asynch DNS lookup */ - return STF_SUSPEND; - } - } - - /* no acceptable key was found: diagnose */ - { - if (s.tried_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "no public key known for '%Y'", peer); - } - else if (s.tried_cnt == 1) - { - loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: " - " wrong key?; tried %d", peer, s.tried_cnt); - DBG(DBG_CONTROL, - DBG_log("public key for '%Y' failed: " - "decrypted SIG payload into a malformed ECB", peer) - ) - } - else - { - loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: " - "tried %d keys but none worked.", peer, s.tried_cnt); - DBG(DBG_CONTROL, - DBG_log("all %d public keys for '%Y' failed: " - "best decrypted SIG payload into a malformed ECB", - s.tried_cnt, peer) - ) - } - return STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } -} - -static notification_t accept_nonce(struct msg_digest *md, chunk_t *dest, - const char *name) -{ - pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_NONCE]->pbs; - size_t len = pbs_left(nonce_pbs); - - if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len) - { - loglog(RC_LOG_SERIOUS, "%s length not between %d and %d" - , name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE); - return ISAKMP_PAYLOAD_MALFORMED; /* ??? */ - } - free(dest->ptr); - *dest = chunk_create(nonce_pbs->cur, len); - *dest = chunk_clone(*dest); - return ISAKMP_NOTHING_WRONG; -} - -/* encrypt message, sans fixed part of header - * IV is fetched from st->st_new_iv and stored into st->st_iv. - * The theory is that there will be no "backing out", so we commit to IV. - * We also close the pbs. - */ -bool encrypt_message(pb_stream *pbs, struct state *st) -{ - u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr); - size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr); - chunk_t data, iv; - char *new_iv; - size_t crypter_block_size, crypter_iv_size; - encryption_algorithm_t enc_alg; - crypter_t *crypter; - - DBG_cond_dump(DBG_CRYPT | DBG_RAW, "encrypting:\n", enc_start, enc_len); - enc_alg = oakley_to_encryption_algorithm(st->st_oakley.encrypt); - crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, st->st_enc_key.len); - crypter_block_size = crypter->get_block_size(crypter); - crypter_iv_size = crypter->get_iv_size(crypter); - - /* Pad up to multiple of encryption blocksize. - * See the description associated with the definition of - * struct isakmp_hdr in packet.h. - */ - { - size_t padding = pad_up(enc_len, crypter_block_size); - - if (padding != 0) - { - if (!out_zero(padding, pbs, "encryption padding")) - return FALSE; - enc_len += padding; - } - } - - DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt))); - data = chunk_create(enc_start, enc_len); - - /* form iv by truncation */ - st->st_new_iv_len = crypter_iv_size; - iv = chunk_create(st->st_new_iv, st->st_new_iv_len); - - crypter->set_key(crypter, st->st_enc_key); - crypter->encrypt(crypter, data, iv, NULL); - crypter->destroy(crypter); - - new_iv = data.ptr + data.len - crypter_iv_size; - memcpy(st->st_new_iv, new_iv, crypter_iv_size); - update_iv(st); - DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len); - close_message(pbs); - return TRUE; -} - -/* Compute HASH(1), HASH(2) of Quick Mode. - * HASH(1) is part of Quick I1 message. - * HASH(2) is part of Quick R1 message. - * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2 - * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25) - */ -static size_t quick_mode_hash12(u_char *dest, u_char *start, u_char *roof, - const struct state *st, const msgid_t *msgid, - bool hash2) -{ - chunk_t msgid_chunk = chunk_from_thing(*msgid); - chunk_t msg_chunk = { start, roof - start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - size_t prf_block_size; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - if (hash2) - { - prf->get_bytes(prf, st->st_ni, NULL); /* include Ni_b in the hash */ - } - prf->get_bytes(prf, msg_chunk, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG(DBG_CRYPT, - DBG_log("HASH(%d) computed:", hash2 + 1); - DBG_dump("", dest, prf_block_size) - ) - return prf_block_size; -} - -/* Compute HASH(3) in Quick Mode (part of Quick I2 message). - * Used by: quick_inR1_outI2, quick_inI2 - * See RFC2409 "The Internet Key Exchange (IKE)" 5.5. - * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the - * Message ID and Nonces. This is a mistake. - */ -static size_t quick_mode_hash3(u_char *dest, struct state *st) -{ - chunk_t seed_chunk = chunk_from_chars(0x00); - chunk_t msgid_chunk = chunk_from_thing(st->st_msgid); - pseudo_random_function_t prf_alg; - prf_t *prf; - size_t prf_block_size; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, seed_chunk, NULL ); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, st->st_ni, NULL); - prf->get_bytes(prf, st->st_nr, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, prf_block_size); - return prf_block_size; -} - -/* Compute Phase 2 IV. - * Uses Phase 1 IV from st_iv; puts result in st_new_iv. - */ -void init_phase2_iv(struct state *st, const msgid_t *msgid) -{ - chunk_t iv_chunk = { st->st_ph1_iv, st->st_ph1_iv_len }; - chunk_t msgid_chunk = chunk_from_thing(*msgid); - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = oakley_to_hash_algorithm(st->st_oakley.hash); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - - DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:", - st->st_ph1_iv, st->st_ph1_iv_len); - - st->st_new_iv_len = hasher->get_hash_size(hasher); - passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); - - hasher->get_hash(hasher, iv_chunk, NULL); - hasher->get_hash(hasher, msgid_chunk, st->st_new_iv); - hasher->destroy(hasher); - - DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:", - st->st_new_iv, st->st_new_iv_len); -} - -/* Initiate quick mode. - * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ] - * (see RFC 2409 "IKE" 5.5) - * Note: this is not called from demux.c - */ - -static bool emit_subnet_id(ip_subnet *net, u_int8_t np, u_int8_t protoid, - u_int16_t port, pb_stream *outs) -{ - struct isakmp_ipsec_id id; - pb_stream id_pbs; - ip_address ta; - const unsigned char *tbp; - size_t tal; - - id.isaiid_np = np; - id.isaiid_idtype = subnetishost(net) - ? aftoinfo(subnettypeof(net))->id_addr - : aftoinfo(subnettypeof(net))->id_subnet; - id.isaiid_protoid = protoid; - id.isaiid_port = port; - - if (!out_struct(&id, &isakmp_ipsec_identification_desc, outs, &id_pbs)) - { - return FALSE; - } - networkof(net, &ta); - tal = addrbytesptr(&ta, &tbp); - if (!out_raw(tbp, tal, &id_pbs, "client network")) - { - return FALSE; - } - if (!subnetishost(net)) - { - maskof(net, &ta); - tal = addrbytesptr(&ta, &tbp); - if (!out_raw(tbp, tal, &id_pbs, "client mask")) - { - return FALSE; - } - } - close_output_pbs(&id_pbs); - return TRUE; -} - -stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, - connection_t *c, lset_t policy, unsigned long try, - so_serial_t replacing) -{ - struct state *st = duplicate_state(isakmp_sa); - pb_stream reply; /* not really a reply */ - pb_stream rbody; - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - bool has_client = c->spd.this.has_client || c->spd.that.has_client || - c->spd.this.protocol || c->spd.that.protocol || - c->spd.this.port || c->spd.that.port; - bool send_natoa = FALSE; - u_int8_t np = ISAKMP_NEXT_NONE; - connection_t *ph1_c = isakmp_sa->st_connection; - - if (c->spd.this.modecfg && !c->spd.this.has_client && - c->spd.this.host_srcip->is_anyaddr(c->spd.this.host_srcip)) - { - host_t * ph1_srcip = ph1_c->spd.this.host_srcip; - - if (ph1_c->spd.this.modecfg && !ph1_srcip->is_anyaddr(ph1_srcip)) - { - c->spd.this.host_srcip->destroy(c->spd.this.host_srcip); - c->spd.this.host_srcip = ph1_srcip->clone(ph1_srcip); - c->spd.this.client = ph1_c->spd.this.client; - c->spd.this.has_client = TRUE; - plog("inheriting virtual IP source address %H from ModeCfg", ph1_srcip); - } - } - - if (ph1_c->policy & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK) && - ph1_c->xauth_identity && !c->xauth_identity) - { - DBG(DBG_CONTROL, - DBG_log("inheriting XAUTH identity %Y", ph1_c->xauth_identity) - ) - c->xauth_identity = ph1_c->xauth_identity->clone(ph1_c->xauth_identity); - } - - st->st_whack_sock = whack_sock; - st->st_connection = c; - set_cur_state(st); /* we must reset before exit */ - st->st_policy = policy; - st->st_try = try; - - st->st_myuserprotoid = c->spd.this.protocol; - st->st_peeruserprotoid = c->spd.that.protocol; - st->st_myuserport = c->spd.this.port; - st->st_peeruserport = c->spd.that.port; - - st->st_msgid = generate_msgid(isakmp_sa); - st->st_state = STATE_QUICK_I1; - - insert_state(st); /* needs cookies, connection, and msgid */ - - if (replacing == SOS_NOBODY) - { - plog("initiating Quick Mode %s {using isakmp#%lu}", - prettypolicy(policy), isakmp_sa->st_serialno); - } - else - { - plog("initiating Quick Mode %s to replace #%lu {using isakmp#%lu}", - prettypolicy(policy), replacing, isakmp_sa->st_serialno); - } - if (isakmp_sa->nat_traversal & NAT_T_DETECTED) - { - /* Duplicate nat_traversal status in new state */ - st->nat_traversal = isakmp_sa->nat_traversal; - - if (isakmp_sa->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) - { - has_client = TRUE; - } - nat_traversal_change_port_lookup(NULL, st); - } - else - { - st->nat_traversal = 0; - } - - /* are we going to send a NAT-OA payload? */ - if ((st->nat_traversal & NAT_T_WITH_NATOA) - && !(st->st_policy & POLICY_TUNNEL) - && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))) - { - send_natoa = TRUE; - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS; - } - - /* set up reply */ - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - /* HDR* out */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_QUICK; - hdr.isa_msgid = st->st_msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* HASH(1) -- create and note space to be filled later */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA); - - /* SA out */ - - /* - * See if pfs_group has been specified for this conn, - * if not, fallback to old use-same-as-P1 behaviour - */ -#ifndef NO_IKE_ALG - if (st->st_connection) - { - st->st_pfs_group = ike_alg_pfsgroup(st->st_connection, policy); - } - if (!st->st_pfs_group) -#endif - /* If PFS specified, use the same group as during Phase 1: - * since no negotiation is possible, we pick one that is - * very likely supported. - */ - st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL; - - /* Emit SA payload based on a subset of the policy bits. - * POLICY_COMPRESS is considered iff we can do IPcomp. - */ - { - lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE; - - if (can_do_IPcomp) - { - pm |= POLICY_COMPRESS; - } - if (!out_sa(&rbody, - &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT], - st, FALSE, ISAKMP_NEXT_NONCE)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &rbody - , policy & POLICY_PFS? ISAKMP_NEXT_KE : has_client? ISAKMP_NEXT_ID : np - , "Ni")) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* [ KE ] out (for PFS) */ - - if (st->st_pfs_group != NULL) - { - if (!build_and_ship_KE(st, &st->st_gi, st->st_pfs_group - , &rbody, has_client? ISAKMP_NEXT_ID : np)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* [ IDci, IDcr ] out */ - if (has_client) - { - /* IDci (we are initiator), then IDcr (peer is responder) */ - if (!emit_subnet_id(&c->spd.this.client - , ISAKMP_NEXT_ID, st->st_myuserprotoid, st->st_myuserport, &rbody) - || !emit_subnet_id(&c->spd.that.client - , np, st->st_peeruserprotoid, st->st_peeruserport, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Send NAT-OA if our address is NATed */ - if (send_natoa) - { - if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* finish computing HASH(1), inserting it in output */ - (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur - , st, &st->st_msgid, FALSE); - - /* encrypt message, except for fixed part of header */ - - init_phase2_iv(isakmp_sa, &st->st_msgid); - st->st_new_iv_len = isakmp_sa->st_new_iv_len; - memcpy(st->st_new_iv, isakmp_sa->st_new_iv, st->st_new_iv_len); - - if (!encrypt_message(&rbody, st)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* save packet, now that we know its size */ - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* send the packet */ - - send_packet(st, "quick_outI1"); - - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - - if (replacing == SOS_NOBODY) - { - whack_log(RC_NEW_STATE + STATE_QUICK_I1 - , "%s: initiate" - , enum_name(&state_names, st->st_state)); - } - else - { - whack_log(RC_NEW_STATE + STATE_QUICK_I1 - , "%s: initiate to replace #%lu" - , enum_name(&state_names, st->st_state) - , replacing); - } - reset_cur_state(); - return STF_OK; -} - - -/* - * Decode the CERT payload of Phase 1. - */ -static void decode_cert(struct msg_digest *md) -{ - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_CERT]; p != NULL; p = p->next) - { - struct isakmp_cert *const cert = &p->payload.cert; - chunk_t blob; - time_t valid_until; - blob.ptr = p->pbs.cur; - blob.len = pbs_left(&p->pbs); - if (cert->isacert_type == CERT_X509_SIGNATURE) - { - cert_t x509cert = cert_empty; - - x509cert.cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); - if (x509cert.cert) - { - if (verify_x509cert(&x509cert, strict_crl_policy, &valid_until)) - { - DBG(DBG_PARSING, - DBG_log("Public key validated") - ) - add_public_key_from_cert(&x509cert, valid_until, DAL_SIGNED); - } - else - { - plog("X.509 certificate rejected"); - } - x509cert.cert->destroy(x509cert.cert); - } - else - { - plog("Syntax error in X.509 certificate"); - } - } - else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509) - { - linked_list_t *certs = linked_list_create(); - - if (pkcs7_parse_signedData(blob, NULL, certs, NULL, NULL)) - { - store_x509certs(certs, strict_crl_policy); - } - else - { - plog("Syntax error in PKCS#7 wrapped X.509 certificates"); - } - certs->destroy_offset(certs, offsetof(certificate_t, destroy)); - } - else - { - loglog(RC_LOG_SERIOUS, "ignoring %s certificate payload", - enum_show(&cert_type_names, cert->isacert_type)); - DBG_cond_dump_chunk(DBG_PARSING, "CERT:\n", blob); - } - } -} - -/* - * Decode the CR payload of Phase 1. - */ -static void decode_cr(struct msg_digest *md, connection_t *c) -{ - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_CR]; p != NULL; p = p->next) - { - struct isakmp_cr *const cr = &p->payload.cr; - chunk_t ca_name; - - ca_name.len = pbs_left(&p->pbs); - ca_name.ptr = (ca_name.len > 0)? p->pbs.cur : NULL; - - DBG_cond_dump_chunk(DBG_PARSING, "CR", ca_name); - - if (cr->isacr_type == CERT_X509_SIGNATURE) - { - if (ca_name.len > 0) - { - identification_t *ca; - - if (!is_asn1(ca_name)) - { - continue; - } - if (c->requested_ca == NULL) - { - c->requested_ca = linked_list_create(); - } - ca = identification_create_from_encoding(ID_DER_ASN1_DN, ca_name); - c->requested_ca->insert_last(c->requested_ca, ca); - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("requested CA: \"%Y\"", ca) - ) - } - else - { - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("requested CA: %%any") - ) - } - c->got_certrequest = TRUE; - } - else - { - loglog(RC_LOG_SERIOUS, "ignoring %s certificate request payload", - enum_show(&cert_type_names, cr->isacr_type)); - } - } -} - -/* Decode the ID payload of Phase 1 (main_inI3_outR3 and main_inR3) - * Note: we may change connections as a result. - * We must be called before SIG or HASH are decoded since we - * may change the peer's public key or ID. - */ -static bool decode_peer_id(struct msg_digest *md, identification_t **peer) -{ - struct state *const st = md->st; - struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID]; - const pb_stream *const id_pbs = &id_pld->pbs; - struct isakmp_id *const id = &id_pld->payload.id; - chunk_t id_payload; - - /* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused. - * It talks about the protocol ID and Port fields of the ID - * Payload, but they don't exist as such in Phase 1. - * We use more appropriate names. - * isaid_doi_specific_a is in place of Protocol ID. - * isaid_doi_specific_b is in place of Port. - * Besides, there is no good reason for allowing these to be - * other than 0 in Phase 1. - */ - if ((st->nat_traversal & NAT_T_WITH_PORT_FLOATING) - && id->isaid_doi_specific_a == IPPROTO_UDP - && (id->isaid_doi_specific_b == 0 || id->isaid_doi_specific_b == NAT_T_IKE_FLOAT_PORT)) - { - DBG_log("protocol/port in Phase 1 ID Payload is %d/%d. " - "accepted with port_floating NAT-T", - id->isaid_doi_specific_a, id->isaid_doi_specific_b); - } - else if (!(id->isaid_doi_specific_a == 0 && id->isaid_doi_specific_b == 0) - && !(id->isaid_doi_specific_a == IPPROTO_UDP && id->isaid_doi_specific_b == IKE_UDP_PORT)) - { - loglog(RC_LOG_SERIOUS, "protocol/port in Phase 1 ID Payload must be 0/0 or %d/%d" - " but are %d/%d" - , IPPROTO_UDP, IKE_UDP_PORT - , id->isaid_doi_specific_a, id->isaid_doi_specific_b); - return FALSE; - } - - id_payload = chunk_create(id_pbs->cur, pbs_left(id_pbs)); - - switch (id->isaid_idtype) - { - case ID_IPV4_ADDR: - if (id_payload.len != 4) - { - loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_IPV6_ADDR: - if (id_payload.len != 16) - { - loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_USER_FQDN: - case ID_FQDN: - if (memchr(id_payload.ptr, '\0', id_payload.len) != NULL) - { - loglog(RC_LOG_SERIOUS, "%s Phase 1 ID payload contains " - "a NUL character", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_KEY_ID: - case ID_DER_ASN1_DN: - break; - default: - /* XXX Could send notification back */ - loglog(RC_LOG_SERIOUS, "unacceptable identity type (%s) " - "in Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - *peer = identification_create_from_encoding(id->isaid_idtype, id_payload); - - plog("Peer ID is %s: '%Y'", enum_show(&ident_names, id->isaid_idtype), - *peer); - - /* check for certificates */ - decode_cert(md); - return TRUE; -} - -/* Now that we've decoded the ID payload, let's see if we - * need to switch connections. - * We must not switch horses if we initiated: - * - if the initiation was explicit, we'd be ignoring user's intent - * - if opportunistic, we'll lose our HOLD info - */ -static bool switch_connection(struct msg_digest *md, identification_t *peer, - bool initiator) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - identification_t *peer_ca; - - peer_ca = st->st_peer_pubkey ? st->st_peer_pubkey->issuer : NULL; - if (peer_ca) - { - DBG(DBG_CONTROL, - DBG_log("peer CA: \"%Y\"", peer_ca) - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("peer CA: %%none") - ) - } - - if (initiator) - { - int pathlen; - - if (!peer->equals(peer, c->spd.that.id)) - { - loglog(RC_LOG_SERIOUS, - "we require peer to have ID '%Y', but peer declares '%Y'", - c->spd.that.id, peer); - return FALSE; - } - - if (c->spd.that.ca) - { - DBG(DBG_CONTROL, - DBG_log("required CA: \"%s\"", c->spd.that.ca); - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("required CA: %%none"); - ) - } - - if (!trusted_ca(peer_ca, c->spd.that.ca, &pathlen)) - { - loglog(RC_LOG_SERIOUS - , "we don't accept the peer's CA"); - return FALSE; - } - } - else - { - connection_t *r; - - /* check for certificate requests */ - decode_cr(md, c); - - r = refine_host_connection(st, peer, peer_ca); - - /* delete the collected certificate requests */ - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - c->requested_ca = NULL; - } - - if (r == NULL) - { - loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%Y'", peer); - return FALSE; - } - - if (r->spd.this.ca) - { - DBG(DBG_CONTROL, - DBG_log("offered CA: \"%Y\"", r->spd.this.ca) - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("offered CA: %%none") - ) - } - - if (r != c) - { - /* apparently, r is an improvement on c -- replace */ - - DBG(DBG_CONTROL - , DBG_log("switched from \"%s\" to \"%s\"", c->name, r->name)); - if (r->kind == CK_TEMPLATE) - { - /* instantiate it, filling in peer's ID */ - r = rw_instantiate(r, &c->spd.that.host_addr - , c->spd.that.host_port, NULL, peer); - } - - /* copy certificate request info */ - r->got_certrequest = c->got_certrequest; - - st->st_connection = r; /* kill reference to c */ - set_cur_connection(r); - connection_discard(c); - } - else if (c->spd.that.has_id_wildcards) - { - c->spd.that.id->destroy(c->spd.that.id); - c->spd.that.id = peer->clone(peer); - c->spd.that.has_id_wildcards = FALSE; - } - } - return TRUE; -} - -/* Decode the variable part of an ID packet (during Quick Mode). - * This is designed for packets that identify clients, not peers. - * Rejects 0.0.0.0/32 or IPv6 equivalent because - * (1) it is wrong and (2) we use this value for inband signalling. - */ -static bool decode_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, - ip_subnet *net, const char *which) -{ - const struct af_info *afi = NULL; - - /* Note: the following may be a pointer into static memory - * that may be recycled, but only if the type is not known. - * That case is disposed of very early -- in the first switch. - */ - const char *idtypename = enum_show(&ident_names, id->isaiid_idtype); - - switch (id->isaiid_idtype) - { - case ID_IPV4_ADDR: - case ID_IPV4_ADDR_SUBNET: - case ID_IPV4_ADDR_RANGE: - afi = &af_inet4_info; - break; - case ID_IPV6_ADDR: - case ID_IPV6_ADDR_SUBNET: - case ID_IPV6_ADDR_RANGE: - afi = &af_inet6_info; - break; - case ID_FQDN: - return TRUE; - default: - /* XXX support more */ - loglog(RC_LOG_SERIOUS, "unsupported ID type %s" - , idtypename); - /* XXX Could send notification back */ - return FALSE; - } - - switch (id->isaiid_idtype) - { - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - { - ip_address temp_address; - err_t ugh; - - ugh = initaddr(id_pbs->cur, pbs_left(id_pbs), afi->af, &temp_address); - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s has wrong length in Quick I1 (%s)" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - if (isanyaddr(&temp_address)) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s is invalid (%s) in Quick I1" - , which, idtypename, ip_str(&temp_address)); - /* XXX Could send notification back */ - return FALSE; - } - happy(addrtosubnet(&temp_address, net)); - DBG(DBG_PARSING | DBG_CONTROL - , DBG_log("%s is %s", which, ip_str(&temp_address))); - break; - } - - case ID_IPV4_ADDR_SUBNET: - case ID_IPV6_ADDR_SUBNET: - { - ip_address temp_address, temp_mask; - err_t ugh; - - if (pbs_left(id_pbs) != 2 * afi->ia_sz) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1" - , which, idtypename); - /* XXX Could send notification back */ - return FALSE; - } - ugh = initaddr(id_pbs->cur - , afi->ia_sz, afi->af, &temp_address); - if (ugh == NULL) - { - ugh = initaddr(id_pbs->cur + afi->ia_sz - , afi->ia_sz, afi->af, &temp_mask); - } - if (ugh == NULL) - { - ugh = initsubnet(&temp_address, masktocount(&temp_mask) - , '0', net); - } - if (ugh == NULL && subnetisnone(net)) - { - ugh = "contains only anyaddr"; - } - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s bad subnet in Quick I1 (%s)" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - DBG(DBG_PARSING | DBG_CONTROL, - { - char temp_buff[SUBNETTOT_BUF]; - - subnettot(net, 0, temp_buff, sizeof(temp_buff)); - DBG_log("%s is subnet %s", which, temp_buff); - }); - break; - } - - case ID_IPV4_ADDR_RANGE: - case ID_IPV6_ADDR_RANGE: - { - ip_address temp_address_from, temp_address_to; - err_t ugh; - - if (pbs_left(id_pbs) != 2 * afi->ia_sz) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1" - , which, idtypename); - /* XXX Could send notification back */ - return FALSE; - } - ugh = initaddr(id_pbs->cur, afi->ia_sz, afi->af, &temp_address_from); - if (ugh == NULL) - { - ugh = initaddr(id_pbs->cur + afi->ia_sz - , afi->ia_sz, afi->af, &temp_address_to); - } - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s malformed (%s) in Quick I1" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - - ugh = rangetosubnet(&temp_address_from, &temp_address_to, net); - if (ugh == NULL && subnetisnone(net)) - { - ugh = "contains only anyaddr"; - } - if (ugh != NULL) - { - char temp_buff1[ADDRTOT_BUF], temp_buff2[ADDRTOT_BUF]; - - addrtot(&temp_address_from, 0, temp_buff1, sizeof(temp_buff1)); - addrtot(&temp_address_to, 0, temp_buff2, sizeof(temp_buff2)); - loglog(RC_LOG_SERIOUS, "%s ID payload in Quick I1, %s" - " %s - %s unacceptable: %s" - , which, idtypename, temp_buff1, temp_buff2, ugh); - return FALSE; - } - DBG(DBG_PARSING | DBG_CONTROL, - { - char temp_buff[SUBNETTOT_BUF]; - - subnettot(net, 0, temp_buff, sizeof(temp_buff)); - DBG_log("%s is subnet %s (received as range)" - , which, temp_buff); - }); - break; - } - } - - /* set the port selector */ - setportof(htons(id->isaiid_port), &net->addr); - - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("%s protocol/port is %d/%d", which, id->isaiid_protoid, id->isaiid_port) - ) - - return TRUE; -} - -/* like decode, but checks that what is received matches what was sent */ -static bool check_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, - u_int8_t *protoid, u_int16_t *port, ip_subnet *net, - const char *which) -{ - ip_subnet net_temp; - - if (!decode_net_id(id, id_pbs, &net_temp, which)) - { - return FALSE; - } - if (!samesubnet(net, &net_temp) - || *protoid != id->isaiid_protoid || *port != id->isaiid_port) - { - loglog(RC_LOG_SERIOUS, "%s ID returned doesn't match my proposal", which); - return FALSE; - } - return TRUE; -} - -/* - * look for the existence of a non-expiring preloaded public key - */ -static bool has_preloaded_public_key(struct state *st) -{ - connection_t *c = st->st_connection; - - /* do not consider rw connections since - * the peer's identity must be known - */ - if (c->kind == CK_PERMANENT) - { - pubkey_list_t *p; - - /* look for a matching RSA public key */ - for (p = pubkeys; p != NULL; p = p->next) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - - if (type == KEY_RSA && - c->spd.that.id->equals(c->spd.that.id, key->id) && - key->until_time == UNDEFINED_TIME) - { - /* found a preloaded public key */ - return TRUE; - } - } - } - return FALSE; -} - -/* Compute keying material for an SA - */ -static void compute_keymat_internal(struct state *st, u_int8_t protoid, - ipsec_spi_t spi, size_t needed_len, - u_char **keymat_out) -{ - size_t i = 0, prf_block_size, needed_space; - chunk_t protoid_chunk = chunk_from_thing(protoid); - chunk_t spi_chunk = chunk_from_thing(spi); - pseudo_random_function_t prf_alg = oakley_to_prf(st->st_oakley.hash); - prf_t *prf = lib->crypto->create_prf(lib->crypto, prf_alg); - - prf->set_key(prf, st->st_skeyid_d); - prf_block_size = prf->get_block_size(prf); - - /* Although only needed_len bytes are desired, we must round up to a - * multiple of prf_block_size so that the buffer isn't overrun */ - needed_space = needed_len + pad_up(needed_len, prf_block_size); - replace(*keymat_out, malloc(needed_space)); - - for (;;) - { - char *keymat_i = (*keymat_out) + i; - chunk_t keymat = { keymat_i, prf_block_size }; - - if (st->st_shared.ptr != NULL) - { /* PFS: include the g^xy */ - prf->get_bytes(prf, st->st_shared, NULL); - } - prf->get_bytes(prf, protoid_chunk, NULL); - prf->get_bytes(prf, spi_chunk, NULL); - prf->get_bytes(prf, st->st_ni, NULL); - prf->get_bytes(prf, st->st_nr, keymat_i); - - i += prf_block_size; - if (i >= needed_space) - { - break; - } - - /* more keying material needed: prepare to go around again */ - prf->get_bytes(prf, keymat, NULL); - } - prf->destroy(prf); -} - -/* - * Produce the new key material of Quick Mode. - * RFC 2409 "IKE" section 5.5 - * specifies how this is to be done. - */ -static void compute_proto_keymat(struct state *st, u_int8_t protoid, - struct ipsec_proto_info *pi, enum endpoint ep) -{ - size_t needed_len = 0; /* bytes of keying material needed */ - - /* Add up the requirements for keying material - * (It probably doesn't matter if we produce too much!) - */ - switch (protoid) - { - case PROTO_IPSEC_ESP: - { - needed_len = kernel_alg_esp_enc_keylen(pi->attrs.transid); - - if (needed_len && pi->attrs.key_len) - { - needed_len = pi->attrs.key_len / BITS_PER_BYTE; - } - - switch (pi->attrs.transid) - { - case ESP_NULL: - needed_len = 0; - break; - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - needed_len += 3; - break; - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_CTR: - case ESP_AES_GMAC: - needed_len += 4; - break; - default: - if (needed_len == 0) - { - bad_case(pi->attrs.transid); - } - } - - if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) - { - needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth); - } - else - { - switch (pi->attrs.auth) - { - case AUTH_ALGORITHM_NONE: - break; - case AUTH_ALGORITHM_HMAC_MD5: - needed_len += HMAC_MD5_KEY_LEN; - break; - case AUTH_ALGORITHM_HMAC_SHA1: - needed_len += HMAC_SHA1_KEY_LEN; - break; - case AUTH_ALGORITHM_DES_MAC: - default: - bad_case(pi->attrs.auth); - } - } - break; - } - case PROTO_IPSEC_AH: - { - switch (pi->attrs.transid) - { - case AH_MD5: - needed_len = HMAC_MD5_KEY_LEN; - break; - case AH_SHA: - needed_len = HMAC_SHA1_KEY_LEN; - break; - default: - bad_case(pi->attrs.transid); - } - break; - } - default: - bad_case(protoid); - } - - pi->keymat_len = needed_len; - - if (ep & EP_LOCAL) - { - compute_keymat_internal(st, protoid, pi->our_spi, needed_len, - &pi->our_keymat); - DBG(DBG_CRYPT, - DBG_dump("KEYMAT computed:\n", pi->our_keymat, - pi->keymat_len)); - } - if (ep & EP_REMOTE) - { - compute_keymat_internal(st, protoid, pi->attrs.spi, needed_len, - &pi->peer_keymat); - DBG(DBG_CRYPT, - DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, - pi->keymat_len)); - } -} - -static void compute_keymats(struct state *st, enum endpoint ep) -{ - if (st->st_ah.present) - { - compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah, ep); - } - if (st->st_esp.present) - { - compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp, ep); - } -} - -static void wipe_proto_keymat(struct ipsec_proto_info *pi, enum endpoint ep) -{ - if (ep & EP_LOCAL) - { - memwipe(pi->our_keymat, pi->keymat_len); - } - if (ep & EP_REMOTE) - { - memwipe(pi->peer_keymat, pi->keymat_len); - } -} - -static void wipe_keymats(struct state *st, enum endpoint ep) -{ - if (st->st_ah.present) - { - wipe_proto_keymat(&st->st_ah, ep); - } - if (st->st_esp.present) - { - wipe_proto_keymat(&st->st_esp, ep); - } -} - -static bool uses_pubkey_auth(int auth) -{ - switch (auth) - { - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - return TRUE; - default: - return FALSE; - } -} - -/* build an ID payload - * Note: no memory is allocated for the body of the payload (tl->ptr). - * We assume it will end up being a pointer into a sufficiently - * stable datastructure. It only needs to last a short time. - */ -static void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) -{ - identification_t *id = resolve_myid(end->id); - - zero(hd); - hd->isaiid_idtype = id->get_type(id); - - switch (id->get_type(id)) - { - case ID_ANY: - hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr; - tl->len = addrbytesptr(&end->host_addr, - (const unsigned char **)&tl->ptr); /* sets tl->ptr too */ - break; - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - case ID_FQDN: - case ID_USER_FQDN: - case ID_DER_ASN1_DN: - case ID_KEY_ID: - *tl = id->get_encoding(id); - break; - default: - bad_case(id->get_type(id)); - } -} - -/* State Transition Functions. - * - * The definition of state_microcode_table in demux.c is a good - * overview of these routines. - * - * - Called from process_packet; result handled by complete_state_transition - * - struct state_microcode member "processor" points to these - * - these routine definitionss are in state order - * - these routines must be restartable from any point of error return: - * beware of memory allocated before any error. - * - output HDR is usually emitted by process_packet (if state_microcode - * member first_out_payload isn't ISAKMP_NEXT_NONE). - * - * The transition functions' functions include: - * - process and judge payloads - * - update st_iv (result of decryption is in st_new_iv) - * - build reply packet - */ - -/* Handle a Main Mode Oakley first packet (responder side). - * HDR;SA --> HDR;SA - */ -stf_status main_inI1_outR1(struct msg_digest *md) -{ - struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; - struct state *st; - connection_t *c; - struct isakmp_proposal proposal; - pb_stream proposal_pbs; - pb_stream r_sa_pbs; - u_int32_t ipsecdoisit; - lset_t policy = LEMPTY; - int vids_to_send = 0; - - /* We preparse the peer's proposal in order to determine - * the requested authentication policy (RSA or PSK) - */ - RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sa_pd->payload.sa - , &sa_pd->pbs, &ipsecdoisit, &proposal_pbs, &proposal)); - - backup_pbs(&proposal_pbs); - RETURN_STF_FAILURE(parse_isakmp_policy(&proposal_pbs - , proposal.isap_notrans, &policy)); - restore_pbs(&proposal_pbs); - - /* We are only considering candidate connections that match - * the requested authentication policy (RSA or PSK) - */ - c = find_host_connection(&md->iface->addr, pluto_port - , &md->sender, md->sender_port, policy); - - if (c == NULL && md->iface->ike_float) - { - c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT - , &md->sender, md->sender_port, policy); - } - - if (c == NULL) - { - /* See if a wildcarded connection can be found. - * We cannot pick the right connection, so we're making a guess. - * All Road Warrior connections are fair game: - * we pick the first we come across (if any). - * If we don't find any, we pick the first opportunistic - * with the smallest subnet that includes the peer. - * There is, of course, no necessary relationship between - * an Initiator's address and that of its client, - * but Food Groups kind of assumes one. - */ - { - connection_t *d; - - d = find_host_connection(&md->iface->addr - , pluto_port, (ip_address*)NULL, md->sender_port, policy); - - for (; d != NULL; d = d->hp_next) - { - if (d->kind == CK_GROUP) - { - /* ignore */ - } - else - { - if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO)) - { - /* must be Road Warrior: we have a winner */ - c = d; - break; - } - - /* Opportunistic or Shunt: pick tightest match */ - if (addrinsubnet(&md->sender, &d->spd.that.client) - && (c == NULL || !subnetinsubnet(&c->spd.that.client, &d->spd.that.client))) - c = d; - } - } - } - - if (c == NULL) - { - loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u" - " but no connection has been authorized%s%s" - , ip_str(&md->iface->addr), ntohs(portof(&md->iface->addr)) - , (policy != LEMPTY) ? " with policy=" : "" - , (policy != LEMPTY) ? bitnamesof(sa_policy_bit_names, policy) : ""); - /* XXX notification is in order! */ - return STF_IGNORE; - } - else if (c->kind != CK_TEMPLATE) - { - loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u" - " but \"%s\" forbids connection" - , ip_str(&md->iface->addr), pluto_port, c->name); - /* XXX notification is in order! */ - return STF_IGNORE; - } - else - { - /* Create a temporary connection that is a copy of this one. - * His ID isn't declared yet. - */ - c = rw_instantiate(c, &md->sender, md->sender_port, NULL, NULL); - } - } - else if (c->kind == CK_TEMPLATE) - { - /* Create an instance - * This is a rare case: wildcard peer ID but static peer IP address - */ - c = rw_instantiate(c, &md->sender, md->sender_port, NULL, c->spd.that.id); - } - - /* Set up state */ - md->st = st = new_state(); - st->st_connection = c; - set_cur_state(st); /* (caller will reset cur_state) */ - st->st_try = 0; /* not our job to try again from start */ - st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */ - - memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE); - get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender); - - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - st->st_doi = ISAKMP_DOI_IPSEC; - st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */ - - if ((c->kind == CK_INSTANCE) && (c->spd.that.host_port != pluto_port)) - { - plog("responding to Main Mode from unknown peer %s:%u" - , ip_str(&c->spd.that.host_addr), c->spd.that.host_port); - } - else if (c->kind == CK_INSTANCE) - { - plog("responding to Main Mode from unknown peer %s" - , ip_str(&c->spd.that.host_addr)); - } - else - { - plog("responding to Main Mode"); - } - - /* parse_isakmp_sa also spits out a winning SA into our reply, - * so we have to build our md->reply and emit HDR before calling it. - */ - - /* determine how many Vendor ID payloads we will be sending */ - if (SEND_PLUTO_VID) - { - vids_to_send++; - } - if (SEND_CISCO_UNITY_VID) - { - vids_to_send++; - } - if (md->openpgp) - { - vids_to_send++; - } - if (SEND_XAUTH_VID) - { - vids_to_send++; - } - /* always send DPD Vendor ID */ - vids_to_send++; - if (md->nat_traversal_vid && nat_traversal_enabled) - { - vids_to_send++; - } - - /* HDR out. - * We can't leave this to comm_handle() because we must - * fill in the cookie. - */ - { - struct isakmp_hdr r_hdr = md->hdr; - - r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */ - memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - r_hdr.isa_np = ISAKMP_NEXT_SA; - if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) - return STF_INTERNAL_ERROR; - } - - /* start of SA out */ - { - struct isakmp_sa r_sa = sa_pd->payload.sa; - - r_sa.isasa_np = vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; - - if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) - return STF_INTERNAL_ERROR; - } - - /* SA body in and out */ - RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit, &proposal_pbs - ,&proposal, &r_sa_pbs, st, FALSE)); - - /* if enabled send Pluto Vendor ID */ - if (SEND_PLUTO_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_STRONGSWAN)) - { - return STF_INTERNAL_ERROR; - } - } - - /* if enabled send Cisco Unity Vendor ID */ - if (SEND_CISCO_UNITY_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_CISCO_UNITY)) - { - return STF_INTERNAL_ERROR; - } - } - - /* - * if the peer sent an OpenPGP Vendor ID we offer the same capability - */ - if (md->openpgp) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_OPENPGP)) - { - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do eXtended AUTHentication to the peer */ - if (SEND_XAUTH_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_MISC_XAUTH)) - { - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do Dead Peer Detection to the peer */ - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_MISC_DPD)) - { - return STF_INTERNAL_ERROR; - } - - if (md->nat_traversal_vid && nat_traversal_enabled) - { - /* reply if NAT-Traversal draft is supported */ - st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid); - - if (st->nat_traversal - && !out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, md->nat_traversal_vid)) - { - return STF_INTERNAL_ERROR; - } - } - - close_message(&md->rbody); - - /* save initiator SA for HASH */ - free(st->st_p1isa.ptr); - st->st_p1isa = chunk_create(sa_pd->pbs.start, pbs_room(&sa_pd->pbs)); - st->st_p1isa = chunk_clone(st->st_p1isa); - - return STF_OK; -} - -/* STATE_MAIN_I1: HDR, SA --> auth dependent - * PSK_AUTH, DS_AUTH: --> HDR, KE, Ni - * - * The following are not yet implemented: - * PKE_AUTH: --> HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r - * RPKE_AUTH: --> HDR, [ HASH(1), ] Pubkey_r, Ke_i, - * Ke_i [,<Ke_i] - * - * We must verify that the proposal received matches one we sent. - */ -stf_status main_inR1_outI2(struct msg_digest *md) -{ - struct state *const st = md->st; - - u_int8_t np = ISAKMP_NEXT_NONE; - - /* verify echoed SA */ - { - u_int32_t ipsecdoisit; - pb_stream proposal_pbs; - struct isakmp_proposal proposal; - struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; - - RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sapd->payload.sa - ,&sapd->pbs, &ipsecdoisit, &proposal_pbs, &proposal)); - if (proposal.isap_notrans != 1) - { - loglog(RC_LOG_SERIOUS, "a single Transform is required in a selecting Oakley Proposal; found %u" - , (unsigned)proposal.isap_notrans); - RETURN_STF_FAILURE(ISAKMP_BAD_PROPOSAL_SYNTAX); - } - RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit - , &proposal_pbs, &proposal, NULL, st, TRUE)); - } - - if (nat_traversal_enabled && md->nat_traversal_vid) - { - st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid); - plog("enabling possible NAT-traversal with method %s" - , bitnamesof(natt_type_bitnames, st->nat_traversal)); - } - if (st->nat_traversal & NAT_T_WITH_NATD) - { - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS; - } - - /**************** build output packet HDR;KE;Ni ****************/ - - /* HDR out. - * We can't leave this to comm_handle() because the isa_np - * depends on the type of Auth (eventually). - */ - echo_hdr(md, FALSE, ISAKMP_NEXT_KE); - - /* KE out */ - if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group - , &md->rbody, ISAKMP_NEXT_NONCE)) - { - return STF_INTERNAL_ERROR; - } - -#ifdef DEBUG - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &md->rbody - , (cur_debugging & IMPAIR_BUST_MI2)? ISAKMP_NEXT_VID : np, "Ni")) - { - return STF_INTERNAL_ERROR; - } - if (cur_debugging & IMPAIR_BUST_MI2) - { - /* generate a pointless large VID payload to push message over MTU */ - pb_stream vid_pbs; - - if (!out_generic(np, &isakmp_vendor_id_desc, &md->rbody, &vid_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&vid_pbs); - } -#else - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &md->rbody, np, "Ni")) - { - return STF_INTERNAL_ERROR; - } -#endif - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) - { - return STF_INTERNAL_ERROR; - } - } - - /* finish message */ - close_message(&md->rbody); - - /* Reinsert the state, using the responder cookie we just received */ - unhash_state(st); - memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE); - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - return STF_OK; -} - -/* STATE_MAIN_R1: - * PSK_AUTH, DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr - * - * The following are not yet implemented: - * PKE_AUTH: HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r - * --> HDR, KE, PubKey_i, PubKey_i - * RPKE_AUTH: - * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] - * --> HDR, PubKey_i, Ke_r, Ke_r - */ -stf_status main_inI2_outR2(struct msg_digest *md) -{ - struct state *const st = md->st; - pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; - - /* send CR if auth is RSA or ECDSA and no preloaded public key exists*/ - bool pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - bool send_cr = !no_cr_send && pubkey_auth && !has_preloaded_public_key(st); - - u_int8_t np = ISAKMP_NEXT_NONE; - - /* KE in */ - RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs)); - - /* Ni in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - nat_traversal_natd_lookup(md); - - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS; - } - if (st->nat_traversal) - { - nat_traversal_show_result(st->nat_traversal, md->sender_port); - } - if (st->nat_traversal & NAT_T_WITH_KA) - { - nat_traversal_new_ka_event(); - } - - /* decode certificate requests */ - st->st_connection->got_certrequest = FALSE; - decode_cr(md, st->st_connection); - - /**************** build output packet HDR;KE;Nr ****************/ - - /* HDR out done */ - - /* KE out */ - if (!build_and_ship_KE(st, &st->st_gr, st->st_oakley.group - , &md->rbody, ISAKMP_NEXT_NONCE)) - { - return STF_INTERNAL_ERROR; - } - -#ifdef DEBUG - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody, - (cur_debugging & IMPAIR_BUST_MR2)? ISAKMP_NEXT_VID - : (send_cr? ISAKMP_NEXT_CR : np), "Nr")) - { - return STF_INTERNAL_ERROR; - } - if (cur_debugging & IMPAIR_BUST_MR2) - { - /* generate a pointless large VID payload to push message over MTU */ - pb_stream vid_pbs; - - if (!out_generic((send_cr)? ISAKMP_NEXT_CR : np, - &isakmp_vendor_id_desc, &md->rbody, &vid_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&vid_pbs); - } -#else - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody, - (send_cr)? ISAKMP_NEXT_CR : np, "Nr")) - return STF_INTERNAL_ERROR; -#endif - - /* CR out */ - if (send_cr) - { - if (st->st_connection->kind == CK_PERMANENT) - { - identification_t *ca = st->st_connection->spd.that.ca; - chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; - - if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, np)) - { - return STF_INTERNAL_ERROR; - } - } - else - { - linked_list_t *list = collect_rw_ca_candidates(md); - int count = list->get_count(list); - bool error = FALSE; - - if (count) - { - enumerator_t *enumerator; - identification_t *ca; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &ca)) - { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, - ca->get_encoding(ca), &md->rbody, - --count ? ISAKMP_NEXT_CR : np)) - { - error = TRUE; - break; - } - } - enumerator->destroy(enumerator); - } - else - { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, chunk_empty, - &md->rbody, np)) - { - error = TRUE; - } - } - list->destroy_offset(list, offsetof(identification_t, destroy)); - if (error) - { - return STF_INTERNAL_ERROR; - } - } - } - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) - { - return STF_INTERNAL_ERROR; - } - } - - /* finish message */ - close_message(&md->rbody); - - /* next message will be encrypted, but not this one. - * We could defer this calculation. - */ - compute_dh_shared(st, st->st_gi); - if (!generate_skeyids_iv(st)) - { - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - update_iv(st); - - return STF_OK; -} - -/* STATE_MAIN_I2: - * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I - * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I - * - * The following are not yet implemented. - * SMF_PKE_AUTH: HDR, KE, PubKey_i, PubKey_i - * --> HDR*, HASH_I - * SMF_RPKE_AUTH: HDR, PubKey_i, Ke_r, Ke_r - * --> HDR*, HASH_I - */ -stf_status main_inR2_outI3(struct msg_digest *md) -{ - struct state *const st = md->st; - pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; - pb_stream id_pbs; /* ID Payload; also used for hash calculation */ - - connection_t *c = st->st_connection; - certpolicy_t cert_policy = c->spd.this.sendcert; - cert_t *mycert = c->spd.this.cert; - bool requested, send_cert, send_cr; - bool pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - - int auth_payload = pubkey_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH; - - /* KE in */ - RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs)); - - /* Nr in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); - - /* decode certificate requests */ - c->got_certrequest = FALSE; - decode_cr(md, c); - - /* free collected certificate requests since as initiator - * we don't heed them anyway - */ - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - c->requested_ca = NULL; - } - - /* send certificate if auth is RSA, we have one and we want - * or are requested to send it - */ - requested = cert_policy == CERT_SEND_IF_ASKED && c->got_certrequest; - send_cert = pubkey_auth && mycert && - mycert->cert->get_type(mycert->cert) == CERT_X509 && - (cert_policy == CERT_ALWAYS_SEND || requested); - - /* send certificate request if we don't have a preloaded RSA public key */ - send_cr = !no_cr_send && send_cert && !has_preloaded_public_key(st); - - /* done parsing; initialize crypto */ - compute_dh_shared(st, st->st_gr); - if (!generate_skeyids_iv(st)) - { - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - if (st->nat_traversal & NAT_T_WITH_NATD) - { - nat_traversal_natd_lookup(md); - } - if (st->nat_traversal) - { - nat_traversal_show_result(st->nat_traversal, md->sender_port); - } - if (st->nat_traversal & NAT_T_WITH_KA) - { - nat_traversal_new_ka_event(); - } - - /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/ - /* ??? NOTE: this is almost the same as main_inI3_outR3's code */ - - /* HDR* out done */ - - /* IDii out */ - { - struct isakmp_ipsec_id id_hd; - chunk_t id_b; - - build_id_payload(&id_hd, &id_b, &c->spd.this); - id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload; - if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs) - || !out_chunk(id_b, &id_pbs, "my identity")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&id_pbs); - } - - /* CERT out */ - if (pubkey_auth) - { - DBG(DBG_CONTROL, - DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) - ) - if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) - { - const char *request_text = ""; - - if (cert_policy == CERT_SEND_IF_ASKED) - { - request_text = (send_cert)? "upon request":"without request"; - } - plog("we have a cert %s sending it %s" - , send_cert? "and are":"but are not", request_text); - } - else - { - plog("we don't have a cert"); - } - } - if (send_cert) - { - bool success = FALSE; - chunk_t cert_encoding; - pb_stream cert_pbs; - - struct isakmp_cert cert_hd; - cert_hd.isacert_np = (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG; - cert_hd.isacert_type = CERT_X509_SIGNATURE; - - if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (mycert->cert->get_encoding(mycert->cert, CERT_ASN1_DER, - &cert_encoding)) - { - success = out_chunk(cert_encoding, &cert_pbs, "CERT"); - free(cert_encoding.ptr); - } - if (!success) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&cert_pbs); - } - - /* CR out */ - if (send_cr) - { - identification_t *ca = st->st_connection->spd.that.ca; - chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; - - if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, ISAKMP_NEXT_SIG)) - { - return STF_INTERNAL_ERROR; - } - } - - /* HASH_I or SIG_I out */ - { - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - - main_mode_hash(st, &hash, TRUE, &id_pbs); - - if (auth_payload == ISAKMP_NEXT_HASH) - { - /* HASH_I out */ - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody, - hash.ptr, hash.len, "HASH_I")) - { - return STF_INTERNAL_ERROR; - } - } - else - { - /* SIG_I out */ - u_char sig_val[RSA_MAX_OCTETS]; - signature_scheme_t scheme; - size_t sig_len; - - scheme = oakley_to_signature_scheme(st->st_oakley.auth); - - sig_len = sign_hash(scheme, c, sig_val, hash); - if (sig_len == 0) - { - loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature"); - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc - , &md->rbody, sig_val, sig_len, "SIG_I")) - { - return STF_INTERNAL_ERROR; - } - } - } - - /* encrypt message, except for fixed part of header */ - - /* st_new_iv was computed by generate_skeyids_iv */ - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - return STF_OK; -} - -/* Shared logic for asynchronous lookup of DNS KEY records. - * Used for STATE_MAIN_R2 and STATE_MAIN_I3. - */ - -enum key_oppo_step { - kos_null, - kos_his_txt -#ifdef USE_KEYRR - , kos_his_key -#endif -}; - -struct key_continuation { - struct adns_continuation ac; /* common prefix */ - struct msg_digest *md; - enum key_oppo_step step; - bool failure_ok; - err_t last_ugh; -}; - -typedef stf_status (key_tail_fn)(struct msg_digest *md - , struct key_continuation *kc); - -static void report_key_dns_failure(identification_t *id, err_t ugh) -{ - loglog(RC_LOG_SERIOUS, "no RSA public key known for '%Y'" - "; DNS search for KEY failed (%s)", id, ugh); -} - - -/* Processs the Main Mode ID Payload and the Authenticator - * (Hash or Signature Payload). - * If a DNS query is still needed to get the other host's public key, - * the query is initiated and STF_SUSPEND is returned. - * Note: parameter kc is a continuation containing the results from - * the previous DNS query, or NULL indicating no query has been issued. - */ -static stf_status -main_id_and_auth(struct msg_digest *md - , bool initiator /* are we the Initiator? */ - , cont_fn_t cont_fn /* continuation function */ - , const struct key_continuation *kc /* current state, can be NULL */ -) -{ - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - struct state *st = md->st; - identification_t *peer; - stf_status r = STF_OK; - - /* ID Payload in */ - if (!decode_peer_id(md, &peer)) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* Hash the ID Payload. - * main_mode_hash requires idpl->cur to be at end of payload - * so we temporarily set if so. - */ - { - pb_stream *idpl = &md->chain[ISAKMP_NEXT_ID]->pbs; - u_int8_t *old_cur = idpl->cur; - - idpl->cur = idpl->roof; - main_mode_hash(st, &hash, !initiator, idpl); - idpl->cur = old_cur; - } - - switch (st->st_oakley.auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - { - pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; - - if (pbs_left(hash_pbs) != hash.len - || memcmp(hash_pbs->cur, hash.ptr, hash.len) != 0) - { - DBG_cond_dump(DBG_CRYPT, "received HASH:" - , hash_pbs->cur, pbs_left(hash_pbs)); - loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value"); - /* XXX Could send notification back */ - r = STF_FAIL + ISAKMP_INVALID_HASH_INFORMATION; - } - } - break; - - case OAKLEY_RSA_SIG: - case XAUTHInitRSA: - case XAUTHRespRSA: - r = check_signature(KEY_RSA, peer, st, hash, - &md->chain[ISAKMP_NEXT_SIG]->pbs, -#ifdef USE_KEYRR - kc == NULL ? NULL : kc->ac.keys_from_dns, -#endif /* USE_KEYRR */ - kc == NULL ? NULL : kc->ac.gateways_from_dns - ); - - if (r == STF_SUSPEND) - { - err_t ugh = NULL; -#ifdef ADNS - /* initiate/resume asynchronous DNS lookup for key */ - struct key_continuation *nkc = malloc_thing(struct key_continuation); - enum key_oppo_step step_done = kc == NULL? kos_null : kc->step; - - /* Record that state is used by a suspended md */ - passert(st->st_suspended_md == NULL); - st->st_suspended_md = md; - - nkc->failure_ok = FALSE; - nkc->md = md; - - switch (step_done) - { - case kos_null: - /* first try: look for the TXT records */ - nkc->step = kos_his_txt; -#ifdef USE_KEYRR - nkc->failure_ok = TRUE; -#endif - ugh = start_adns_query(peer, peer, T_TXT, cont_fn, &nkc->ac); - break; - -#ifdef USE_KEYRR - case kos_his_txt: - /* second try: look for the KEY records */ - nkc->step = kos_his_key; - ugh = start_adns_query(peer, NULL, T_KEY, cont_fn, &nkc->ac); - break; -#endif /* USE_KEYRR */ - - default: - bad_case(step_done); - } -#else /* ADNS */ - ugh = "adns not supported"; -#endif /* ADNS */ - if (ugh != NULL) - { - report_key_dns_failure(peer, ugh); - st->st_suspended_md = NULL; - r = STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } - } - break; - - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - r = check_signature(KEY_ECDSA, peer, st, hash, - &md->chain[ISAKMP_NEXT_SIG]->pbs, -#ifdef USE_KEYRR - NULL, -#endif /* USE_KEYRR */ - NULL); - break; - - default: - bad_case(st->st_oakley.auth); - } - if (r != STF_OK) - { - peer->destroy(peer); - return r; - } - DBG(DBG_CRYPT, DBG_log("authentication succeeded")); - - /* - * With the peer ID known, let's see if we need to switch connections. - */ - if (!switch_connection(md, peer, initiator)) - { - r = STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - peer->destroy(peer); - return r; -} - -/* This continuation is called as part of either - * the main_inI3_outR3 state or main_inR3 state. - * - * The "tail" function is the corresponding tail - * function main_inI3_outR3_tail | main_inR3_tail, - * either directly when the state is started, or via - * adns continuation. - * - * Basically, we go around in a circle: - * main_in?3* -> key_continue - * ^ \ - * / V - * adns main_in?3*_tail - * ^ | - * \ V - * main_id_and_auth - * - * until such time as main_id_and_auth is able - * to find authentication, or we run out of things - * to try. - */ -static void key_continue(struct adns_continuation *cr, err_t ugh, - key_tail_fn *tail) -{ - struct key_continuation *kc = (void *)cr; - struct state *st = kc->md->st; - - passert(cur_state == NULL); - - /* if st == NULL, our state has been deleted -- just clean up */ - if (st != NULL) - { - stf_status r; - - passert(st->st_suspended_md == kc->md); - st->st_suspended_md = NULL; /* no longer connected or suspended */ - cur_state = st; - - if (!kc->failure_ok && ugh != NULL) - { - report_key_dns_failure(st->st_connection->spd.that.id, ugh); - r = STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } - else - { - -#ifdef USE_KEYRR - passert(kc->step == kos_his_txt || kc->step == kos_his_key); -#else - passert(kc->step == kos_his_txt); -#endif - kc->last_ugh = ugh; /* record previous error in case we need it */ - r = (*tail)(kc->md, kc); - } - complete_state_transition(&kc->md, r); - } - if (kc->md != NULL) - { - release_md(kc->md); - } - cur_state = NULL; -} - -/* STATE_MAIN_R2: - * PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R - * DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R - * PKE_AUTH, RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R - * - * Broken into parts to allow asynchronous DNS lookup. - * - * - main_inI3_outR3 to start - * - main_inI3_outR3_tail to finish or suspend for DNS lookup - * - main_inI3_outR3_continue to start main_inI3_outR3_tail again - */ -static key_tail_fn main_inI3_outR3_tail; /* forward */ - -stf_status main_inI3_outR3(struct msg_digest *md) -{ - return main_inI3_outR3_tail(md, NULL); -} - -static void main_inI3_outR3_continue(struct adns_continuation *cr, err_t ugh) -{ - key_continue(cr, ugh, main_inI3_outR3_tail); -} - -static stf_status -main_inI3_outR3_tail(struct msg_digest *md -, struct key_continuation *kc) -{ - struct state *const st = md->st; - u_int8_t auth_payload; - pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */ - certpolicy_t cert_policy; - cert_t *mycert; - bool pubkey_auth, send_cert, requested; - - /* ID and HASH_I or SIG_I in - * Note: this may switch the connection being used! - */ - { - stf_status r = main_id_and_auth(md, FALSE - , main_inI3_outR3_continue - , kc); - - if (r != STF_OK) - { - return r; - } - } - - /* send certificate if pubkey authentication is used, we have one - * and we want or are requested to send it - */ - cert_policy = st->st_connection->spd.this.sendcert; - mycert = st->st_connection->spd.this.cert; - requested = cert_policy == CERT_SEND_IF_ASKED - && st->st_connection->got_certrequest; - pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - send_cert = pubkey_auth && mycert && - mycert->cert->get_type(mycert->cert) == CERT_X509 && - (cert_policy == CERT_ALWAYS_SEND || requested); - - /*************** build output packet HDR*;IDir;HASH/SIG_R ***************/ - /* proccess_packet() would automatically generate the HDR* - * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE. - * We don't do this because we wish there to be no partially - * built output packet if we need to suspend for asynch DNS. - */ - /* ??? NOTE: this is almost the same as main_inR2_outI3's code */ - - /* HDR* out - * If auth were PKE_AUTH or RPKE_AUTH, ISAKMP_NEXT_HASH would - * be first payload. - */ - echo_hdr(md, TRUE, ISAKMP_NEXT_ID); - - auth_payload = pubkey_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH; - - /* IDir out */ - { - /* id_hd should be struct isakmp_id, but struct isakmp_ipsec_id - * allows build_id_payload() to work for both phases. - */ - struct isakmp_ipsec_id id_hd; - chunk_t id_b; - - build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this); - id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload; - if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs) - || !out_chunk(id_b, &r_id_pbs, "my identity")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&r_id_pbs); - } - - /* CERT out */ - if (pubkey_auth) - { - DBG(DBG_CONTROL, - DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) - ) - if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) - { - const char *request_text = ""; - - if (cert_policy == CERT_SEND_IF_ASKED) - { - request_text = (send_cert)? "upon request":"without request"; - } - plog("we have a cert %s sending it %s" - , send_cert? "and are":"but are not", request_text); - } - else - { - plog("we don't have a cert"); - } - } - if (send_cert) - { - bool success = FALSE; - chunk_t cert_encoding; - pb_stream cert_pbs; - struct isakmp_cert cert_hd; - - cert_hd.isacert_np = ISAKMP_NEXT_SIG; - cert_hd.isacert_type = CERT_X509_SIGNATURE; - - if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (mycert->cert->get_encoding(mycert->cert, CERT_ASN1_DER, - &cert_encoding)) - { - success = out_chunk(cert_encoding, &cert_pbs, "CERT"); - free(cert_encoding.ptr); - } - if (!success) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&cert_pbs); - } - - /* HASH_R or SIG_R out */ - { - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - - main_mode_hash(st, &hash, FALSE, &r_id_pbs); - - if (auth_payload == ISAKMP_NEXT_HASH) - { - /* HASH_R out */ - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody, - hash.ptr, hash.len, "HASH_R")) - { - return STF_INTERNAL_ERROR; - } - } - else - { - /* SIG_R out */ - u_char sig_val[RSA_MAX_OCTETS]; - signature_scheme_t scheme; - size_t sig_len; - - scheme = oakley_to_signature_scheme(st->st_oakley.auth); - - sig_len = sign_hash(scheme, st->st_connection, sig_val, hash); - if (sig_len == 0) - { - loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature"); - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc - , &md->rbody, sig_val, sig_len, "SIG_R")) - { - return STF_INTERNAL_ERROR; - } - } - } - - /* encrypt message, sans fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - - /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */ - DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:" - , st->st_new_iv, st->st_new_iv_len); - - ISAKMP_SA_established(st->st_connection, st->st_serialno); - - /* Save Phase 1 IV */ - st->st_ph1_iv_len = st->st_new_iv_len; - set_ph1_iv(st, st->st_new_iv); - - return STF_OK; -} - -/* STATE_MAIN_I3: - * Handle HDR*;IDir;HASH/SIG_R from responder. - * - * Broken into parts to allow asynchronous DNS for KEY records. - * - * - main_inR3 to start - * - main_inR3_tail to finish or suspend for DNS lookup - * - main_inR3_continue to start main_inR3_tail again - */ - -static key_tail_fn main_inR3_tail; /* forward */ - -stf_status main_inR3(struct msg_digest *md) -{ - return main_inR3_tail(md, NULL); -} - -static void main_inR3_continue(struct adns_continuation *cr, err_t ugh) -{ - key_continue(cr, ugh, main_inR3_tail); -} - -static stf_status main_inR3_tail(struct msg_digest *md, - struct key_continuation *kc) -{ - struct state *const st = md->st; - - /* ID and HASH_R or SIG_R in - * Note: this may switch the connection being used! - */ - { - stf_status r = main_id_and_auth(md, TRUE, main_inR3_continue, kc); - - if (r != STF_OK) - { - return r; - } - } - - /**************** done input ****************/ - - ISAKMP_SA_established(st->st_connection, st->st_serialno); - - /* Save Phase 1 IV */ - st->st_ph1_iv_len = st->st_new_iv_len; - set_ph1_iv(st, st->st_new_iv); - - - update_iv(st); /* finalize our Phase 1 IV */ - - return STF_OK; -} - -/* Handle first message of Phase 2 -- Quick Mode. - * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] - * (see RFC 2409 "IKE" 5.5) - * Installs inbound IPsec SAs. - * Although this seems early, we know enough to do so, and - * this way we know that it is soon enough to catch all - * packets that other side could send using this IPsec SA. - * - * Broken into parts to allow asynchronous DNS for TXT records: - * - * - quick_inI1_outR1 starts the ball rolling. - * It checks and parses enough to learn the Phase 2 IDs - * - * - quick_inI1_outR1_tail does the rest of the job - * unless DNS must be consulted. In that case, - * it starts a DNS query, salts away what is needed - * to continue, and suspends. Calls - * + quick_inI1_outR1_start_query - * + quick_inI1_outR1_process_answer - * - * - quick_inI1_outR1_continue will restart quick_inI1_outR1_tail - * when DNS comes back with an answer. - * - * A big chunk of quick_inI1_outR1_tail is executed twice. - * This is necessary because the set of connections - * might change while we are awaiting DNS. - * When first called, gateways_from_dns == NULL. If DNS is - * consulted asynchronously, gateways_from_dns != NULL the second time. - * Remember that our state object might disappear too! - * - * - * If the connection is opportunistic, we must verify delegation. - * - * 1. Check that we are authorized to be SG for - * our client. We look for the TXT record that - * delegates us. We also check that the public - * key (if present) matches the private key we used. - * Eventually, we should probably require DNSsec - * authentication for our side. - * - * 2. If our client TXT record did not include a - * public key, check the KEY record indicated - * by the identity in the TXT record. - * - * 3. If the peer's client is the peer itself, we - * consider it authenticated. Otherwise, we check - * the TXT record for the client to see that - * the identity of the SG matches the peer and - * that some public key (if present in the TXT) - * matches. We need not check the public key if - * it isn't in the TXT record. - * - * Since p isn't yet instantiated, we need to look - * in c for description of peer. - * - * We cannot afford to block waiting for a DNS query. - * The code here is structured as two halves: - * - process the result of just completed - * DNS query (if any) - * - if another query is needed, initiate the next - * DNS query and suspend - */ - -enum verify_oppo_step { - vos_fail, - vos_start, - vos_our_client, - vos_our_txt, -#ifdef USE_KEYRR - vos_our_key, -#endif /* USE_KEYRR */ - vos_his_client, - vos_done -}; - -static const char *const verify_step_name[] = { - "vos_fail", - "vos_start", - "vos_our_client", - "vos_our_txt", -#ifdef USE_KEYRR - "vos_our_key", -#endif /* USE_KEYRR */ - "vos_his_client", - "vos_done" -}; - -/* hold anything we can handle of a Phase 2 ID */ -struct p2id { - ip_subnet net; - u_int8_t proto; - u_int16_t port; -}; - -struct verify_oppo_bundle { - enum verify_oppo_step step; - bool failure_ok; /* if true, quick_inI1_outR1_continue will try - * other things on DNS failure */ - struct msg_digest *md; - struct p2id my, his; - unsigned int new_iv_len; /* p1st's might change */ - u_char new_iv[MAX_DIGEST_LEN]; - /* int whackfd; */ /* not needed because we are Responder */ -}; - -struct verify_oppo_continuation { - struct adns_continuation ac; /* common prefix */ - struct verify_oppo_bundle b; -}; - -static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b - , struct adns_continuation *ac); - -stf_status quick_inI1_outR1(struct msg_digest *md) -{ - const struct state *const p1st = md->st; - connection_t *c = p1st->st_connection; - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - struct verify_oppo_bundle b; - - /* HASH(1) in */ - CHECK_QUICK_HASH(md - , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof - , p1st, &md->hdr.isa_msgid, FALSE) - , "HASH(1)", "Quick I1"); - - /* [ IDci, IDcr ] in - * We do this now (probably out of physical order) because - * we wish to select the correct connection before we consult - * it for policy. - */ - - if (id_pd != NULL) - { - /* ??? we are assuming IPSEC_DOI */ - - /* IDci (initiator is peer) */ - - if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs - , &b.his.net, "peer client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* Hack for MS 818043 NAT-T Update */ - - if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN) - { - happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net)); - } - - /* End Hack for MS 818043 NAT-T Update */ - - b.his.proto = id_pd->payload.ipsec_id.isaiid_protoid; - b.his.port = id_pd->payload.ipsec_id.isaiid_port; - b.his.net.addr.u.v4.sin_port = htons(b.his.port); - - /* IDcr (we are responder) */ - - if (!decode_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs - , &b.my.net, "our client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - b.my.proto = id_pd->next->payload.ipsec_id.isaiid_protoid; - b.my.port = id_pd->next->payload.ipsec_id.isaiid_port; - b.my.net.addr.u.v4.sin_port = htons(b.my.port); - } - else - { - /* implicit IDci and IDcr: peer and self */ - if (!sameaddrtype(&c->spd.this.host_addr, &c->spd.that.host_addr)) - { - return STF_FAIL; - } - happy(addrtosubnet(&c->spd.this.host_addr, &b.my.net)); - happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net)); - b.his.proto = b.my.proto = 0; - b.his.port = b.my.port = 0; - } - b.step = vos_start; - b.md = md; - b.new_iv_len = p1st->st_new_iv_len; - memcpy(b.new_iv, p1st->st_new_iv, p1st->st_new_iv_len); - return quick_inI1_outR1_tail(&b, NULL); -} - -#ifdef ADNS - -static void -report_verify_failure(struct verify_oppo_bundle *b, err_t ugh) -{ - struct state *st = b->md->st; - char fgwb[ADDRTOT_BUF] - , cb[ADDRTOT_BUF]; - ip_address client; - err_t which = NULL; - - switch (b->step) - { - case vos_our_client: - case vos_our_txt: -#ifdef USE_KEYRR - case vos_our_key: -#endif /* USE_KEYRR */ - which = "our"; - networkof(&b->my.net, &client); - break; - - case vos_his_client: - which = "his"; - networkof(&b->his.net, &client); - break; - - case vos_start: - case vos_done: - case vos_fail: - default: - bad_case(b->step); - } - - addrtot(&st->st_connection->spd.that.host_addr, 0, fgwb, sizeof(fgwb)); - addrtot(&client, 0, cb, sizeof(cb)); - loglog(RC_OPPOFAILURE - , "gateway %s wants connection with %s as %s client, but DNS fails to confirm delegation: %s" - , fgwb, cb, which, ugh); -} - -static void quick_inI1_outR1_continue(struct adns_continuation *cr, err_t ugh) -{ - stf_status r; - struct verify_oppo_continuation *vc = (void *)cr; - struct verify_oppo_bundle *b = &vc->b; - struct state *st = b->md->st; - - passert(cur_state == NULL); - /* if st == NULL, our state has been deleted -- just clean up */ - if (st != NULL) - { - passert(st->st_suspended_md == b->md); - st->st_suspended_md = NULL; /* no longer connected or suspended */ - cur_state = st; - if (!b->failure_ok && ugh != NULL) - { - report_verify_failure(b, ugh); - r = STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else - { - r = quick_inI1_outR1_tail(b, cr); - } - complete_state_transition(&b->md, r); - } - if (b->md != NULL) - { - release_md(b->md); - } - cur_state = NULL; -} - -static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b, - enum verify_oppo_step next_step) -{ - struct msg_digest *md = b->md; - struct state *p1st = md->st; - connection_t *c = p1st->st_connection; - struct verify_oppo_continuation *vc = malloc_thing(struct verify_oppo_continuation); - identification_t *id; /* subject of query */ - identification_t *our_id; /* needed for myid playing */ - identification_t *our_id_space; /* ephemeral: no need for unshare_id_content */ - ip_address client; - err_t ugh = NULL; - - /* Record that state is used by a suspended md */ - b->step = next_step; /* not just vc->b.step */ - vc->b = *b; - passert(p1st->st_suspended_md == NULL); - p1st->st_suspended_md = b->md; - - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - - DBG_log("responding with DNS query - from %s to %s new state: %s" - , ours, his, verify_step_name[b->step]); - }); - - /* Resolve %myid in a cheesy way. - * We have to do the resolution because start_adns_query - * et al have insufficient information to do so. - * If %myid is already known, we'll use that value - * (XXX this may be a mistake: it could be stale). - * If %myid is unknown, we should check to see if - * there are credentials for the IP address or the FQDN. - * Instead, we'll just assume the IP address since we are - * acting as the responder and only the IP address would - * have gotten it to us. - * We don't even try to do this for the other side: - * %myid makes no sense for the other side (but it is syntactically - * legal). - */ - our_id = resolve_myid(c->spd.this.id); - if (our_id->get_type(our_id) == ID_ANY) - { - our_id_space = identification_create_from_sockaddr((sockaddr_t*)&c->spd.this.host_addr); - our_id = our_id_space; - } - - switch (next_step) - { - case vos_our_client: - networkof(&b->my.net, &client); - id = identification_create_from_sockaddr((sockaddr_t*)&client); - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(id - , our_id - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - - case vos_our_txt: - vc->b.failure_ok = b->failure_ok = TRUE; - ugh = start_adns_query(our_id - , our_id /* self as SG */ - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - -#ifdef USE_KEYRR - case vos_our_key: - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(our_id - , NULL - , T_KEY - , quick_inI1_outR1_continue - , &vc->ac); - break; -#endif - - case vos_his_client: - networkof(&b->his.net, &client); - id = identification_create_from_sockaddr((sockaddr_t*)&client); - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(id - , c->spd.that.id - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - - default: - bad_case(next_step); - } - - if (ugh != NULL) - { - /* note: we'd like to use vc->b but vc has been freed - * so we have to use b. This is why we plunked next_state - * into b, not just vc->b. - */ - report_verify_failure(b, ugh); - p1st->st_suspended_md = NULL; - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else - { - return STF_SUSPEND; - } -} - -static enum verify_oppo_step quick_inI1_outR1_process_answer( - struct verify_oppo_bundle *b, - struct adns_continuation *ac, - struct state *p1st) -{ - connection_t *c = p1st->st_connection; - enum verify_oppo_step next_step = vos_our_client; - err_t ugh = NULL; - - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - DBG_log("responding on demand from %s to %s state: %s" - , ours, his, verify_step_name[b->step]); - }); - - /* process just completed DNS query (if any) */ - switch (b->step) - { - case vos_start: - /* no query to digest */ - next_step = vos_our_client; - break; - - case vos_our_client: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - struct gw_info *gwp; - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - ugh = "our client does not delegate us as its Security Gateway"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "our client delegates us as its Security Gateway but with the wrong public key"; - /* If there is no key in the TXT record, - * we count it as a win, but we will have - * to separately fetch and check the KEY record. - * If there is a key from the TXT record, - * we count it as a win if we match the key. - */ - if (!gwp->gw_key_present) - { - next_step = vos_our_txt; - ugh = NULL; /* good! */ - break; - } - else if (private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - break; - - case vos_our_txt: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - { - struct gw_info *gwp; - - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { -#ifdef USE_KEYRR - /* not an error yet, because we have to check KEY RR as well */ - ugh = NULL; -#else - ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; -#endif - if (gwp->gw_key_present - && private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } -#ifdef USE_KEYRR - next_step = vos_our_key; -#endif - } - } - } - break; - -#ifdef USE_KEYRR - case vos_our_key: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - { - pubkey_list_t *kp; - - ugh = "our client delegation depends on our missing " RRNAME " record"; - for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next) - { - ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; - if (private->belongs_to(private, kp->key->public_key)) - { - /* do this only once a day */ - if (!logged_txt_warning) - { - loglog(RC_LOG_SERIOUS, "found KEY RR but not TXT RR. See http://www.freeswan.org/err/txt-change.html."); - logged_txt_warning = TRUE; - } - ugh = NULL; /* good! */ - break; - } - } - } - } - break; -#endif /* USE_KEYRR */ - - case vos_his_client: - next_step = vos_done; - { - public_key_t *pub_key; - struct gw_info *gwp; - - /* check that the public key that authenticated - * the ISAKMP SA (p1st) will do for this gateway. - */ - pub_key = p1st->st_peer_pubkey->public_key; - - ugh = "peer's client does not delegate to peer"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "peer and its client disagree about public key"; - /* If there is a key from the TXT record, - * we count it as a win if we match the key. - * If there was no key, we claim a match since - * it implies fetching a KEY from the same - * place we must have gotten it. - */ - if (!gwp->gw_key_present || - pub_key->equals(pub_key, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - break; - - default: - bad_case(b->step); - } - - if (ugh != NULL) - { - report_verify_failure(b, ugh); - next_step = vos_fail; - } - return next_step; -} - -#endif /* ADNS */ - -static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, - struct adns_continuation *ac) -{ - struct msg_digest *md = b->md; - struct state *const p1st = md->st; - connection_t *c = p1st->st_connection; - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - ip_subnet *our_net = &b->my.net - , *his_net = &b->his.net; - - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* from where to start hashing */ - - /* Now that we have identities of client subnets, we must look for - * a suitable connection (our current one only matches for hosts). - */ - { - connection_t *p = find_client_connection(c - , our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port); - - if (p == NULL) - { - /* This message occurs in very puzzling circumstances - * so we must add as much information and beauty as we can. - */ - struct end - me = c->spd.this, - he = c->spd.that; - char buf[2*SUBNETTOT_BUF + 2*ADDRTOT_BUF + 2*BUF_LEN + 2*ADDRTOT_BUF + 12]; /* + 12 for separating */ - size_t l; - - me.client = *our_net; - me.has_client = !subnetisaddr(our_net, &me.host_addr); - me.protocol = b->my.proto; - me.port = b->my.port; - - he.client = *his_net; - he.has_client = !subnetisaddr(his_net, &he.host_addr); - he.protocol = b->his.proto; - he.port = b->his.port; - - l = format_end(buf, sizeof(buf), &me, NULL, TRUE, LEMPTY); - l += snprintf(buf + l, sizeof(buf) - l, "..."); - (void)format_end(buf + l, sizeof(buf) - l, &he, NULL, FALSE, LEMPTY); - plog("cannot respond to IPsec SA request" - " because no connection is known for %s" - , buf); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else if (p != c) - { - /* We've got a better connection: it can support the - * specified clients. But it may need instantiation. - */ - if (p->kind == CK_TEMPLATE) - { - /* Yup, it needs instantiation. How much? - * Is it a Road Warrior connection (simple) - * or is it an Opportunistic connection (needing gw validation)? - */ - if (p->policy & POLICY_OPPO) - { -#ifdef ADNS - /* Opportunistic case: delegation must be verified. - * Here be dragons. - */ - enum verify_oppo_step next_step; - ip_address our_client, his_client; - - passert(subnetishost(our_net) && subnetishost(his_net)); - networkof(our_net, &our_client); - networkof(his_net, &his_client); - - next_step = quick_inI1_outR1_process_answer(b, ac, p1st); - if (next_step == vos_fail) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* short circuit: if peer's client is self, - * accept that we've verified delegation in Phase 1 - */ - if (next_step == vos_his_client - && sameaddr(&c->spd.that.host_addr, &his_client)) - { - next_step = vos_done; - } - - /* the second chunk: initiate the next DNS query (if any) */ - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - - DBG_log("responding on demand from %s to %s new state: %s" - , ours, his, verify_step_name[next_step]); - }); - - /* start next DNS query and suspend (if necessary) */ - if (next_step != vos_done) - { - return quick_inI1_outR1_start_query(b, next_step); - } - - /* Instantiate inbound Opportunistic connection, - * carrying over authenticated peer ID - * and filling in a few more details. - * We used to include gateways_from_dns, but that - * seems pointless at this stage of negotiation. - * We should record DNS sec use, if any -- belongs in - * state during perhaps. - */ - p = oppo_instantiate(p, &c->spd.that.host_addr, c->spd.that.id - , NULL, &our_client, &his_client); -#else /* ADNS */ - plog("opportunistic connections not supported because" - " adns is not available"); - return STF_INTERNAL_ERROR; -#endif /* ADNS */ - } - else - { - /* Plain Road Warrior: - * instantiate, carrying over authenticated peer ID - */ - host_t *vip = c->spd.that.host_srcip; - - p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port - , his_net, c->spd.that.id); - - /* inherit any virtual IP assigned by a Mode Config exchange */ - if (p->spd.that.modecfg && c->spd.that.modecfg && - subnetisaddr(his_net, (ip_address*)vip->get_sockaddr(vip))) - { - DBG(DBG_CONTROL, - DBG_log("inheriting virtual IP source address %H from ModeCfg", vip) - ) - p->spd.that.host_srcip->destroy(p->spd.that.host_srcip); - p->spd.that.host_srcip = vip->clone(vip); - p->spd.that.client = c->spd.that.client; - p->spd.that.has_client = TRUE; - } - - if (c->policy & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK) && - c->xauth_identity && !p->xauth_identity) - { - DBG(DBG_CONTROL, - DBG_log("inheriting XAUTH identity %Y", c->xauth_identity) - ) - p->xauth_identity = c->xauth_identity->clone(c->xauth_identity); - } - } - } -#ifdef DEBUG - /* temporarily bump up cur_debugging to get "using..." message - * printed if we'd want it with new connection. - */ - { - lset_t old_cur_debugging = cur_debugging; - - cur_debugging |= p->extra_debugging; - DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name)); - cur_debugging = old_cur_debugging; - } -#endif - c = p; - } - /* fill in the client's true ip address/subnet */ - if (p->spd.that.has_client_wildcard) - { - p->spd.that.client = *his_net; - p->spd.that.has_client_wildcard = FALSE; - } - else if (is_virtual_connection(c)) - { - c->spd.that.client = *his_net; - c->spd.that.virt = NULL; - if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net)) - { - c->spd.that.has_client = FALSE; - } - } - - /* fill in the client's true port */ - if (p->spd.that.has_port_wildcard) - { - int port = htons(b->his.port); - - setportof(port, &p->spd.that.host_addr); - setportof(port, &p->spd.that.client.addr); - - p->spd.that.port = b->his.port; - p->spd.that.has_port_wildcard = FALSE; - } - } - - /* now that we are sure of our connection, create our new state */ - { - enum endpoint ep = EP_LOCAL; - struct state *const st = duplicate_state(p1st); - - /* first: fill in missing bits of our new state object - * note: we don't copy over st_peer_pubkey, the public key - * that authenticated the ISAKMP SA. We only need it in this - * routine, so we can "reach back" to p1st to get it. - */ - - if (st->st_connection != c) - { - connection_t *t = st->st_connection; - - st->st_connection = c; - set_cur_connection(c); - connection_discard(t); - } - - st->st_try = 0; /* not our job to try again from start */ - - st->st_msgid = md->hdr.isa_msgid; - - st->st_new_iv_len = b->new_iv_len; - memcpy(st->st_new_iv, b->new_iv, b->new_iv_len); - - set_cur_state(st); /* (caller will reset) */ - md->st = st; /* feed back new state */ - - st->st_peeruserprotoid = b->his.proto; - st->st_peeruserport = b->his.port; - st->st_myuserprotoid = b->my.proto; - st->st_myuserport = b->my.port; - - insert_state(st); /* needs cookies, connection, and msgid */ - - /* copy the connection's - * IPSEC policy into our state. The ISAKMP policy is water under - * the bridge, I think. It will reflect the ISAKMP SA that we - * are using. - */ - st->st_policy = (p1st->st_policy & POLICY_ISAKMP_MASK) - | (c->policy & ~POLICY_ISAKMP_MASK); - - if (p1st->nat_traversal & NAT_T_DETECTED) - { - st->nat_traversal = p1st->nat_traversal; - nat_traversal_change_port_lookup(md, md->st); - } - else - { - st->nat_traversal = 0; - } - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); - } - - /* Start the output packet. - * - * proccess_packet() would automatically generate the HDR* - * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE. - * We don't do this because we wish there to be no partially - * built output packet if we need to suspend for asynch DNS. - * - * We build the reply packet as we parse the message since - * the parse_ipsec_sa_body emits the reply SA - */ - - /* HDR* out */ - echo_hdr(md, TRUE, ISAKMP_NEXT_HASH); - - /* HASH(2) out -- first pass */ - START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA); - - /* process SA (in and out) */ - { - struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; - pb_stream r_sa_pbs; - struct isakmp_sa sa = sapd->payload.sa; - - /* sa header is unchanged -- except for np */ - sa.isasa_np = ISAKMP_NEXT_NONCE; - if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) - { - return STF_INTERNAL_ERROR; - } - - /* parse and accept body */ - st->st_pfs_group = &unset_group; - RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs - , &sapd->payload.sa, &r_sa_pbs, FALSE, st)); - } - - passert(st->st_pfs_group != &unset_group); - - if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL) - { - loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION"); - return STF_FAIL + ISAKMP_NO_PROPOSAL_CHOSEN; - } - - /* Ni in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); - - /* [ KE ] in (for PFS) */ - RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi, "Gi", "Quick Mode I1")); - - plog("responding to Quick Mode"); - - /**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/ - - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody - , st->st_pfs_group != NULL? ISAKMP_NEXT_KE : id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE - , "Nr")) - { - return STF_INTERNAL_ERROR; - } - - /* [ KE ] out (for PFS) */ - - if (st->st_pfs_group != NULL) - { - if (!build_and_ship_KE(st, &st->st_gr, st->st_pfs_group - , &md->rbody, id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE)) - { - return STF_INTERNAL_ERROR; - } - - /* MPZ-Operations might be done after sending the packet... */ - compute_dh_shared(st, st->st_gi); - } - - /* [ IDci, IDcr ] out */ - if (id_pd != NULL) - { - struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */ - - if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci")) - { - return STF_INTERNAL_ERROR; - } - p->isaiid_np = ISAKMP_NEXT_ID; - - p = (void *)md->rbody.cur; /* UGH! */ - - if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr")) - { - return STF_INTERNAL_ERROR; - } - p->isaiid_np = ISAKMP_NEXT_NONE; - } - - if ((st->nat_traversal & NAT_T_WITH_NATOA) - && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) - && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT)) - { - /** Send NAT-OA if our address is NATed and if we use Transport Mode */ - if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &md->rbody, md->st)) - { - return STF_INTERNAL_ERROR; - } - } - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT) - && (c->spd.that.has_client)) - { - /** Remove client **/ - addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client); - c->spd.that.has_client = FALSE; - } - - /* Compute reply HASH(2) and insert in output */ - (void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur - , st, &st->st_msgid, TRUE); - - /* Derive new keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the new inbound SA - * (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_inbound_ipsec_sa(st)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - wipe_keymats(st, ep); - - /* encrypt message, except for fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - - return STF_OK; - } -} - -/* - * Initialize RFC 3706 Dead Peer Detection - */ -static void dpd_init(struct state *st) -{ - struct state *p1st = find_state(st->st_icookie, st->st_rcookie - , &st->st_connection->spd.that.host_addr, 0); - - if (p1st == NULL) - { - loglog(RC_LOG_SERIOUS, "could not find phase 1 state for DPD"); - } - else if (p1st->st_dpd) - { - plog("Dead Peer Detection (RFC 3706) enabled"); - /* randomize the first DPD event */ - - event_schedule(EVENT_DPD - , (0.5 + rand()/(RAND_MAX + 1.E0)) * st->st_connection->dpd_delay - , st); - } -} - -/* Handle (the single) message from Responder in Quick Mode. - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(3) - * (see RFC 2409 "IKE" 5.5) - * Installs inbound and outbound IPsec SAs, routing, etc. - */ -stf_status quick_inR1_outI2(struct msg_digest *md) -{ - enum endpoint ep = EP_LOCAL | EP_REMOTE; - struct state *const st = md->st; - const connection_t *c = st->st_connection; - - /* HASH(2) in */ - CHECK_QUICK_HASH(md - , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof - , st, &st->st_msgid, TRUE) - , "HASH(2)", "Quick R1"); - - /* SA in */ - { - struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; - - RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs - , &sa_pd->payload.sa, NULL, TRUE, st)); - } - - /* Nr in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); - - /* [ KE ] in (for PFS) */ - RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1")); - - if (st->st_pfs_group != NULL) - { - compute_dh_shared(st, st->st_gr); - } - - /* [ IDci, IDcr ] in; these must match what we sent */ - - { - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - - if (id_pd != NULL) - { - /* ??? we are assuming IPSEC_DOI */ - - /* IDci (we are initiator) */ - - if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs - , &st->st_myuserprotoid, &st->st_myuserport - , &st->st_connection->spd.this.client - , "our client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* IDcr (responder is peer) */ - - if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs - , &st->st_peeruserprotoid, &st->st_peeruserport - , &st->st_connection->spd.that.client - , "peer client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - else - { - /* no IDci, IDcr: we must check that the defaults match our proposal */ - if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr) - || !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr)) - { - loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message" - " but default does not match proposal"); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - } - - /* check the peer's group attributes */ - { - identification_t *peer_ca = NULL; - ietf_attributes_t *peer_attributes = NULL; - bool match; - - get_peer_ca_and_groups(st->st_connection, &peer_ca, &peer_attributes); - match = match_group_membership(peer_attributes, - st->st_connection->name, - st->st_connection->spd.that.groups); - DESTROY_IF(peer_attributes); - - if (!match) - { - ietf_attributes_t *groups = st->st_connection->spd.that.groups; - - loglog(RC_LOG_SERIOUS, - "peer with attributes '%s' is not a member of the groups '%s'", - peer_attributes->get_string(peer_attributes), - groups->get_string(groups)); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); - } - - /* ??? We used to copy the accepted proposal into the state, but it was - * never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs). - */ - - /**************** build reply packet HDR*, HASH(3) ****************/ - - /* HDR* out done */ - - /* HASH(3) out -- since this is the only content, no passes needed */ - { - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - - START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE); - (void)quick_mode_hash3(r_hashval, st); - } - - /* Derive new keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the inbound, outbound, and routing part - * of the new SA (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_ipsec_sa(st, TRUE)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; - } - wipe_keymats(st, ep); - - /* encrypt message, except for fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - DBG(DBG_CONTROLMORE, - DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" - , st->st_connection->name - , st->st_connection->instance_serial - , st->st_serialno - , st->st_connection->newest_ipsec_sa - , st->st_connection->spd.eroute_owner) - ) - st->st_connection->newest_ipsec_sa = st->st_serialno; - - /* note (presumed) success */ - if (c->gw_info != NULL) - { - c->gw_info->key->last_worked_time = now(); - } - - /* If we want DPD on this connection then initialize it */ - if (st->st_connection->dpd_action != DPD_ACTION_NONE) - { - dpd_init(st); - } - return STF_OK; -} - -/* Handle last message of Quick Mode. - * HDR*, HASH(3) -> done - * (see RFC 2409 "IKE" 5.5) - * Installs outbound IPsec SAs, routing, etc. - */ -stf_status quick_inI2(struct msg_digest *md) -{ - enum endpoint ep = EP_REMOTE; - struct state *const st = md->st; - - /* HASH(3) in */ - CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st) - , "HASH(3)", "Quick I2"); - - /* Derive keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the outbound and routing part of the new SA - * (the previous state established inbound) - * (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_ipsec_sa(st, FALSE)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; - } - wipe_keymats(st, ep); - - DBG(DBG_CONTROLMORE, - DBG_log("inI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" - , st->st_connection->name - , st->st_connection->instance_serial - , st->st_serialno - , st->st_connection->newest_ipsec_sa - , st->st_connection->spd.eroute_owner) - ) - st->st_connection->newest_ipsec_sa = st->st_serialno; - - update_iv(st); /* not actually used, but tidy */ - - /* note (presumed) success */ - { - struct gw_info *gw = st->st_connection->gw_info; - - if (gw != NULL) - { - gw->key->last_worked_time = now(); - } - } - - /* If we want DPD on this connection then initialize it */ - if (st->st_connection->dpd_action != DPD_ACTION_NONE) - { - dpd_init(st); - } - return STF_OK; -} - -static stf_status send_isakmp_notification(struct state *st, u_int16_t type, - const void *data, size_t len) -{ - msgid_t msgid; - pb_stream reply; - pb_stream rbody; - u_char - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - - msgid = generate_msgid(st); - - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "ISAKMP notify"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - impossible(); - } - } - /* HASH -- create and note space to be filled later */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_N); - - /* NOTIFY */ - { - pb_stream notify_pbs; - struct isakmp_notification isan; - - isan.isan_np = ISAKMP_NEXT_NONE; - isan.isan_doi = ISAKMP_DOI_IPSEC; - isan.isan_protoid = PROTO_ISAKMP; - isan.isan_spisize = COOKIE_SIZE * 2; - isan.isan_type = type; - if (!out_struct(&isan, &isakmp_notification_desc, &rbody, ¬ify_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_raw(st->st_icookie, COOKIE_SIZE, ¬ify_pbs, "notify icookie")) - { - return STF_INTERNAL_ERROR; - } - if (!out_raw(st->st_rcookie, COOKIE_SIZE, ¬ify_pbs, "notify rcookie")) - { - return STF_INTERNAL_ERROR; - } - if (data != NULL && len > 0) - { - if (!out_raw(data, len, ¬ify_pbs, "notify data")) - { - return STF_INTERNAL_ERROR; - } - } - close_output_pbs(¬ify_pbs); - } - - { - /* finish computing HASH */ - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, rbody.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - prf->destroy(prf); - } - - /* Encrypt message (preserve st_iv and st_new_iv) */ - { - u_char old_iv[MAX_DIGEST_LEN]; - u_char new_iv[MAX_DIGEST_LEN]; - - u_int old_iv_len = st->st_iv_len; - u_int new_iv_len = st->st_new_iv_len; - - if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) - return STF_INTERNAL_ERROR; - - memcpy(old_iv, st->st_iv, old_iv_len); - memcpy(new_iv, st->st_new_iv, new_iv_len); - - init_phase2_iv(st, &msgid); - if (!encrypt_message(&rbody, st)) - { - return STF_INTERNAL_ERROR; - } - - /* restore preserved st_iv and st_new_iv */ - memcpy(st->st_iv, old_iv, old_iv_len); - memcpy(st->st_new_iv, new_iv, new_iv_len); - st->st_iv_len = old_iv_len; - st->st_new_iv_len = new_iv_len; - } - - /* Send packet (preserve st_tpacket) */ - { - chunk_t saved_tpacket = st->st_tpacket; - - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - send_packet(st, "ISAKMP notify"); - st->st_tpacket = saved_tpacket; - } - - return STF_IGNORE; -} - -/* - * DPD Out Initiator - */ -void dpd_outI(struct state *p2st) -{ - struct state *st; - u_int32_t seqno; - time_t tm; - time_t idle_time; - time_t delay = p2st->st_connection->dpd_delay; - time_t timeout = p2st->st_connection->dpd_timeout; - - /* find the newest related Phase 1 state */ - st = find_phase1_state(p2st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - - if (st == NULL) - { - loglog(RC_LOG_SERIOUS, "DPD: Could not find newest phase 1 state"); - return; - } - - /* If no DPD, then get out of here */ - if (!st->st_dpd) - { - return; - } - - /* schedule the next periodic DPD event */ - event_schedule(EVENT_DPD, delay, p2st); - - /* Current time */ - tm = now(); - - /* Make sure we really need to invoke DPD */ - if (!was_eroute_idle(p2st, delay, &idle_time)) - { - DBG(DBG_CONTROL, - DBG_log("recent eroute activity %u seconds ago, " - "no need to send DPD notification" - , (int)idle_time) - ) - st->st_last_dpd = tm; - delete_dpd_event(st); - return; - } - - /* If an R_U_THERE has been sent or received recently, or if a - * companion Phase 2 SA has shown eroute activity, - * then we don't need to invoke DPD. - */ - if (tm < st->st_last_dpd + delay) - { - DBG(DBG_CONTROL, - DBG_log("recent DPD activity %u seconds ago, " - "no need to send DPD notification" - , (int)(tm - st->st_last_dpd)) - ) - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - return; - - if (!st->st_dpd_seqno) - { - rng_t *rng; - - /* Get a non-zero random value that has room to grow */ - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->get_bytes(rng, sizeof(st->st_dpd_seqno), (u_char *)&st->st_dpd_seqno); - rng->destroy(rng); - st->st_dpd_seqno &= 0x7fff; - st->st_dpd_seqno++; - } - seqno = htonl(st->st_dpd_seqno); - - if (send_isakmp_notification(st, R_U_THERE, &seqno, sizeof(seqno)) != STF_IGNORE) - { - loglog(RC_LOG_SERIOUS, "DPD: Could not send R_U_THERE"); - return; - } - DBG(DBG_CONTROL, - DBG_log("sent DPD notification R_U_THERE with seqno = %u", st->st_dpd_seqno) - ) - st->st_dpd_expectseqno = st->st_dpd_seqno++; - st->st_last_dpd = tm; - /* Only schedule a new timeout if there isn't one currently, - * or if it would be sooner than the current timeout. */ - if (st->st_dpd_event == NULL - || st->st_dpd_event->ev_time > tm + timeout) - { - delete_dpd_event(st); - event_schedule(EVENT_DPD_TIMEOUT, timeout, st); - } -} - -/* - * DPD in Initiator, out Responder - */ -stf_status -dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *pbs) -{ - time_t tm = now(); - u_int32_t seqno; - - if (st == NULL || !IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "DPD: Received R_U_THERE for unestablished ISAKMP SA"); - return STF_IGNORE; - } - if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid SPI length (%d)", n->isan_spisize); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid icookie (broken Cisco?)"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid rcookie (broken Cisco?)"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; - } - pbs->cur += COOKIE_SIZE; - - if (pbs_left(pbs) != sizeof(seqno)) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid data length (%d)" - , (int) pbs_left(pbs)); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - seqno = ntohl(*(u_int32_t *)pbs->cur); - DBG(DBG_CONTROL, - DBG_log("received DPD notification R_U_THERE with seqno = %u", seqno) - ) - - if (st->st_dpd_peerseqno && seqno <= st->st_dpd_peerseqno) { - loglog(RC_LOG_SERIOUS, "DPD: Received old or duplicate R_U_THERE"); - return STF_IGNORE; - } - - st->st_dpd_peerseqno = seqno; - delete_dpd_event(st); - - if (send_isakmp_notification(st, R_U_THERE_ACK, pbs->cur, pbs_left(pbs)) != STF_IGNORE) - { - loglog(RC_LOG_SERIOUS, "DPD Info: could not send R_U_THERE_ACK"); - return STF_IGNORE; - } - DBG(DBG_CONTROL, - DBG_log("sent DPD notification R_U_THERE_ACK with seqno = %u", seqno) - ) - - st->st_last_dpd = tm; - return STF_IGNORE; -} - -/* - * DPD out Responder - */ -stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, - pb_stream *pbs) -{ - u_int32_t seqno; - - if (st == NULL || !IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS - , "DPD: Received R_U_THERE_ACK for unestablished ISAKMP SA"); - return STF_FAIL; - } - - if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) - { - loglog(RC_LOG_SERIOUS - , "DPD: R_U_THERE_ACK has invalid SPI length (%d)" - , n->isan_spisize); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid icookie"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid rcookie"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (pbs_left(pbs) != sizeof(seqno)) - { - loglog(RC_LOG_SERIOUS - , " DPD: R_U_THERE_ACK has invalid data length (%d)" - , (int) pbs_left(pbs)); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - seqno = ntohl(*(u_int32_t *)pbs->cur); - DBG(DBG_CONTROL, - DBG_log("received DPD notification R_U_THERE_ACK with seqno = %u" - , seqno) - ) - - if (!st->st_dpd_expectseqno && seqno != st->st_dpd_expectseqno) - { - loglog(RC_LOG_SERIOUS - , "DPD: R_U_THERE_ACK has unexpected sequence number %u (expected %u)" - , seqno, st->st_dpd_expectseqno); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - st->st_dpd_expectseqno = 0; - delete_dpd_event(st); - return STF_IGNORE; -} - -/* - * DPD Timeout Function - * - * This function is called when a timeout DPD_EVENT occurs. We set clear/trap - * both the SA and the eroutes, depending on what the connection definition - * tells us (either 'hold' or 'clear') - */ -void -dpd_timeout(struct state *st) -{ - struct state *newest_phase1_st; - connection_t *c = st->st_connection; - int action = st->st_connection->dpd_action; - char cname[BUF_LEN]; - - passert(action == DPD_ACTION_HOLD - || action == DPD_ACTION_CLEAR - || DPD_ACTION_RESTART); - - /* is there a newer phase1_state? */ - newest_phase1_st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - if (newest_phase1_st != NULL && newest_phase1_st != st) - { - plog("DPD: Phase1 state #%ld has been superseded by #%ld" - " - timeout ignored" - , st->st_serialno, newest_phase1_st->st_serialno); - return; - } - - loglog(RC_LOG_SERIOUS, "DPD: No response from peer - declaring peer dead"); - - /* delete the state, which is probably in phase 2 */ - set_cur_connection(c); - plog("DPD: Terminating all SAs using this connection"); - delete_states_by_connection(c, TRUE); - reset_cur_connection(); - - switch (action) - { - case DPD_ACTION_HOLD: - /* dpdaction=hold - Wipe the SA's but %trap the eroute so we don't - * leak traffic. Also, being in %trap means new packets will - * force an initiation of the conn again. - */ - loglog(RC_LOG_SERIOUS, "DPD: Putting connection \"%s\" into %%trap", c->name); - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - break; - case DPD_ACTION_CLEAR: - /* dpdaction=clear - Wipe the SA & eroute - everything */ - loglog(RC_LOG_SERIOUS, "DPD: Clearing connection \"%s\"", c->name); - unroute_connection(c); - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - break; - case DPD_ACTION_RESTART: - /* dpdaction=restart - Restart connection, - * except if roadwarrior connection - */ - loglog(RC_LOG_SERIOUS, "DPD: Restarting connection \"%s\"", c->name); - unroute_connection(c); - - /* caching the connection name before deletion */ - strncpy(cname, c->name, BUF_LEN); - cname[BUF_LEN-1] = '\0'; - - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - initiate_connection(cname, NULL_FD); - break; - default: - loglog(RC_LOG_SERIOUS, "DPD: unknown action"); - } -} - diff --git a/src/pluto/ipsec_doi.h b/src/pluto/ipsec_doi.h deleted file mode 100644 index c11edaa94..000000000 --- a/src/pluto/ipsec_doi.h +++ /dev/null @@ -1,108 +0,0 @@ -/* IPsec DOI and Oakley resolution routines - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _IPSEC_DOI_H -#define _IPSEC_DOI_H - -#include "defs.h" - -extern void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np); - -extern void ipsecdoi_initiate(int whack_sock, struct connection *c - , lset_t policy, unsigned long try, so_serial_t replacing); - -extern void ipsecdoi_replace(struct state *st, unsigned long try); - -extern void init_phase2_iv(struct state *st, const msgid_t *msgid); - -extern stf_status quick_outI1(int whack_sock - , struct state *isakmp_sa - , struct connection *c - , lset_t policy - , unsigned long try - , so_serial_t replacing); - -extern state_transition_fn - main_inI1_outR1, - main_inR1_outI2, - main_inI2_outR2, - main_inR2_outI3, - main_inI3_outR3, - main_inR3, - quick_inI1_outR1, - quick_inR1_outI2, - quick_inI2; - -extern void send_delete(struct state *st); -extern void accept_delete(struct state *st, struct msg_digest *md - , struct payload_digest *p); -extern void close_message(pb_stream *pbs); -extern bool encrypt_message(pb_stream *pbs, struct state *st); - - -extern void send_notification_from_state(struct state *st, - enum state_kind state, u_int16_t type); -extern void send_notification_from_md(struct msg_digest *md, u_int16_t type); - -extern const char *init_pluto_vendorid(void); - -extern void dpd_outI(struct state *st); -extern stf_status dpd_inI_outR(struct state *st - , struct isakmp_notification *const n, pb_stream *n_pbs); -extern stf_status dpd_inR(struct state *st - , struct isakmp_notification *const n, pb_stream *n_pbs); -extern void dpd_timeout(struct state *st); - -/* START_HASH_PAYLOAD - * - * Emit a to-be-filled-in hash payload, noting the field start (r_hashval) - * and the start of the part of the message to be hashed (r_hash_start). - * This macro is magic. - * - it can cause the caller to return - * - it references variables local to the caller (r_hashval, r_hash_start, st) - */ -#define START_HASH_PAYLOAD(rbody, np) { \ - pb_stream hash_pbs; \ - if (!out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \ - return STF_INTERNAL_ERROR; \ - r_hashval = hash_pbs.cur; /* remember where to plant value */ \ - if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) \ - return STF_INTERNAL_ERROR; \ - close_output_pbs(&hash_pbs); \ - r_hash_start = (rbody).cur; /* hash from after HASH payload */ \ -} - -/* CHECK_QUICK_HASH - * - * This macro is magic -- it cannot be expressed as a function. - * - it causes the caller to return! - * - it declares local variables and expects the "do_hash" argument - * expression to reference them (hash_val, hash_pbs) - */ -#define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \ - pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; \ - u_char hash_val[MAX_DIGEST_LEN]; \ - size_t hash_len = do_hash; \ - if (pbs_left(hash_pbs) != hash_len \ - || memcmp(hash_pbs->cur, hash_val, hash_len) != 0) \ - { \ - DBG_cond_dump(DBG_CRYPT, "received " hash_name ":", hash_pbs->cur, pbs_left(hash_pbs)); \ - loglog(RC_LOG_SERIOUS, "received " hash_name " does not match computed value in " msg_name); \ - /* XXX Could send notification back */ \ - return STF_FAIL + ISAKMP_INVALID_HASH_INFORMATION; \ - } \ - } - -#endif /* _IPSEC_DOI_H */ - diff --git a/src/pluto/kameipsec.h b/src/pluto/kameipsec.h deleted file mode 100644 index 5e9d8ce99..000000000 --- a/src/pluto/kameipsec.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __IPSEC_H -#define __IPSEC_H 1 - -/* The definitions, required to talk to KAME racoon IKE. */ - -#define IPSEC_PORT_ANY 0 -#define IPSEC_ULPROTO_ANY 255 -#define IPSEC_PROTO_ANY 255 - -enum { - IPSEC_MODE_ANY = 0, /* We do not support this for SA */ - IPSEC_MODE_TRANSPORT = 1, - IPSEC_MODE_TUNNEL = 2 -}; - -enum { - IPSEC_DIR_ANY = 0, - IPSEC_DIR_INBOUND = 1, - IPSEC_DIR_OUTBOUND = 2, - IPSEC_DIR_FWD = 3, /* It is our own */ - IPSEC_DIR_MAX = 4, - IPSEC_DIR_INVALID = 5 -}; - -enum { - IPSEC_POLICY_DISCARD = 0, - IPSEC_POLICY_NONE = 1, - IPSEC_POLICY_IPSEC = 2, - IPSEC_POLICY_ENTRUST = 3, - IPSEC_POLICY_BYPASS = 4 -}; - -enum { - IPSEC_LEVEL_DEFAULT = 0, - IPSEC_LEVEL_USE = 1, - IPSEC_LEVEL_REQUIRE = 2, - IPSEC_LEVEL_UNIQUE = 3 -}; - -#define IPSEC_MANUAL_REQID_MAX 0x3fff - -#define IPSEC_REPLAYWSIZE 32 - -#define IP_IPSEC_POLICY 16 -#define IPV6_IPSEC_POLICY 34 - -#endif /* __IPSEC_H */ diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c deleted file mode 100644 index e4729ef08..000000000 --- a/src/pluto/kernel.c +++ /dev/null @@ -1,2114 +0,0 @@ -/* routines that interface with the kernel's IPsec mechanism - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998-2002 D. Hugh Redelmeier - * Copyright (C) 1997 Angelos D. Keromytis - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include /* for select(2) */ -#include /* for select(2) */ -#include -#include -#include "kameipsec.h" - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "timer.h" -#include "kernel.h" -#include "kernel_pfkey.h" -#include "log.h" -#include "ca.h" -#include "server.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "keys.h" -#include "crypto.h" -#include "nat_traversal.h" -#include "alg_info.h" -#include "kernel_alg.h" -#include "pluto.h" - - -bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */ - -/* test if the routes required for two different connections agree - * It is assumed that the destination subnets agree; we are only - * testing that the interfaces and nexthops match. - */ -#define routes_agree(c, d) ((c)->interface == (d)->interface \ - && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop)) - -/* forward declaration */ -static bool shunt_eroute(connection_t *c, struct spd_route *sr, - enum routing_t rt_kind, unsigned int op, - const char *opname); - -static void set_text_said(char *text_said, const ip_address *dst, - ipsec_spi_t spi, int proto); - -/** - * Default IPsec SA config (e.g. to install trap policies). - */ -static ipsec_sa_cfg_t null_ipsec_sa = { - .mode = MODE_TRANSPORT, - .esp = { - .use = TRUE, - }, -}; - -/** - * Helper function that converts an ip_subnet to a traffic_selector_t. - */ -static traffic_selector_t *traffic_selector_from_subnet(const ip_subnet *client, - const u_int8_t proto) -{ - traffic_selector_t *ts; - host_t *net; - net = host_create_from_sockaddr((sockaddr_t*)&client->addr); - ts = traffic_selector_create_from_subnet(net, client->maskbits, proto, - net->get_port(net)); - return ts; -} - -/** - * Helper function that converts a traffic_selector_t to an ip_subnet. - */ -static ip_subnet subnet_from_traffic_selector(traffic_selector_t *ts) -{ - ip_subnet subnet; - host_t *net; - u_int8_t mask; - ts->to_subnet(ts, &net, &mask); - subnet.addr = *(ip_address*)net->get_sockaddr(net); - subnet.maskbits = mask; - net->destroy(net); - return subnet; -} - - -void record_and_initiate_opportunistic(const ip_subnet *ours, - const ip_subnet *his, - int transport_proto, const char *why) -{ - ip_address src, dst; - passert(samesubnettype(ours, his)); - - /* actually initiate opportunism */ - networkof(ours, &src); - networkof(his, &dst); - initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD); -} - -/* Generate Unique SPI numbers. - * - * The returned SPI is in network byte order. - */ -ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, - bool tunnel) -{ - host_t *host_src, *host_dst; - u_int32_t spi; - - host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); - - if (hydra->kernel_interface->get_spi(hydra->kernel_interface, host_src, - host_dst, proto, sr->reqid, &spi) != SUCCESS) - { - spi = 0; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return spi; -} - -/* Generate Unique CPI numbers. - * The result is returned as an SPI (4 bytes) in network order! - * The real bits are in the nework-low-order 2 bytes. - */ -ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel) -{ - host_t *host_src, *host_dst; - u_int16_t cpi; - - host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); - - if (hydra->kernel_interface->get_cpi(hydra->kernel_interface, host_src, - host_dst, sr->reqid, &cpi) != SUCCESS) - - { - cpi = 0; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return htonl((u_int32_t)ntohs(cpi)); -} - -/* Replace the shell metacharacters ', \, ", `, and $ in a character string - * by escape sequences consisting of their octal values - */ -static void escape_metachar(const char *src, char *dst, size_t dstlen) -{ - while (*src != '\0' && dstlen > 4) - { - switch (*src) - { - case '\'': - case '\\': - case '"': - case '`': - case '$': - sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src); - dst += 4; - dstlen -= 4; - break; - default: - *dst++ = *src; - dstlen--; - } - src++; - } - *dst = '\0'; -} - -/* invoke the updown script to do the routing and firewall commands required - * - * The user-specified updown script is run. Parameters are fed to it in - * the form of environment variables. All such environment variables - * have names starting with "PLUTO_". - * - * The operation to be performed is specified by PLUTO_VERB. This - * verb has a suffix "-host" if the client on this end is just the - * host; otherwise the suffix is "-client". If the address family - * of the host is IPv6, an extra suffix of "-v6" is added. - * - * "prepare-host" and "prepare-client" are used to delete a route - * that may exist (due to forces outside of Pluto). It is used to - * prepare for pluto creating a route. - * - * "route-host" and "route-client" are used to install a route. - * Since routing is based only on destination, the PLUTO_MY_CLIENT_* - * values are probably of no use (using them may signify a bug). - * - * "unroute-host" and "unroute-client" are used to delete a route. - * Since routing is based only on destination, the PLUTO_MY_CLIENT_* - * values are probably of no use (using them may signify a bug). - * - * "up-host" and "up-client" are run when an eroute is added (not replaced). - * They are useful for adjusting a firewall: usually for adding a rule - * to let processed packets flow between clients. Note that only - * one eroute may exist for a pair of client subnets but inbound - * IPsec SAs may persist without an eroute. - * - * "down-host" and "down-client" are run when an eroute is deleted. - * They are useful for adjusting a firewall. - */ - -#ifndef DEFAULT_UPDOWN -# define DEFAULT_UPDOWN "ipsec _updown" -#endif - -static bool do_command(connection_t *c, struct spd_route *sr, struct state *st, - const char *verb) -{ - char cmd[1536]; /* arbitrary limit on shell command length */ - const char *verb_suffix; - - /* figure out which verb suffix applies */ - { - const char *hs, *cs; - - switch (addrtypeof(&sr->this.host_addr)) - { - case AF_INET: - hs = "-host"; - cs = "-client"; - break; - case AF_INET6: - hs = "-host-v6"; - cs = "-client-v6"; - break; - default: - loglog(RC_LOG_SERIOUS, "unknown address family"); - return FALSE; - } - verb_suffix = subnetisaddr(&sr->this.client, &sr->this.host_addr) - ? hs : cs; - } - - /* form the command string */ - { - char - nexthop_str[sizeof("PLUTO_NEXT_HOP='' ") +ADDRTOT_BUF] = "", - srcip_str[sizeof("PLUTO_MY_SOURCEIP='' ")+ADDRTOT_BUF] = "", - me_str[ADDRTOT_BUF], - myid_str[BUF_LEN], - myclient_str[SUBNETTOT_BUF], - myclientnet_str[ADDRTOT_BUF], - myclientmask_str[ADDRTOT_BUF], - peer_str[ADDRTOT_BUF], - peerid_str[BUF_LEN], - peerclient_str[SUBNETTOT_BUF], - peerclientnet_str[ADDRTOT_BUF], - peerclientmask_str[ADDRTOT_BUF], - peerca_str[BUF_LEN], - mark_in[BUF_LEN] = "", - mark_out[BUF_LEN] = "", - udp_encap[BUF_LEN] = "", - xauth_id_str[BUF_LEN] = "", - secure_myid_str[BUF_LEN] = "", - secure_peerid_str[BUF_LEN] = "", - secure_peerca_str[BUF_LEN] = "", - secure_xauth_id_str[BUF_LEN] = ""; - ip_address ta; - pubkey_list_t *p; - - if (addrbytesptr(&sr->this.host_nexthop, NULL) - && !isanyaddr(&sr->this.host_nexthop)) - { - char *n; - - strcpy(nexthop_str, "PLUTO_NEXT_HOP='"); - n = nexthop_str + strlen(nexthop_str); - - addrtot(&sr->this.host_nexthop, 0 - ,n , sizeof(nexthop_str)-strlen(nexthop_str)); - strncat(nexthop_str, "' ", sizeof(nexthop_str)); - } - - if (!sr->this.host_srcip->is_anyaddr(sr->this.host_srcip)) - { - char *n; - - strcpy(srcip_str, "PLUTO_MY_SOURCEIP='"); - n = srcip_str + strlen(srcip_str); - snprintf(n, sizeof(srcip_str)-strlen(srcip_str), "%H", - sr->this.host_srcip); - strncat(srcip_str, "' ", sizeof(srcip_str)); - } - - if (sr->mark_in.value) - { - snprintf(mark_in, sizeof(mark_in), "PLUTO_MARK_IN='%u/0x%08x' ", - sr->mark_in.value, sr->mark_in.mask); - } - - if (sr->mark_out.value) - { - snprintf(mark_out, sizeof(mark_out), "PLUTO_MARK_OUT='%u/0x%08x' ", - sr->mark_out.value, sr->mark_out.mask); - } - - if (st && (st->nat_traversal & NAT_T_DETECTED)) - { - snprintf(udp_encap, sizeof(udp_encap), "PLUTO_UDP_ENC='%u' ", - sr->that.host_port); - } - - addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); - snprintf(myid_str, sizeof(myid_str), "%Y", sr->this.id); - escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str)); - subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str)); - networkof(&sr->this.client, &ta); - addrtot(&ta, 0, myclientnet_str, sizeof(myclientnet_str)); - maskof(&sr->this.client, &ta); - addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str)); - - if (c->xauth_identity && - c->xauth_identity->get_type(c->xauth_identity) != ID_ANY) - { - snprintf(xauth_id_str, sizeof(xauth_id_str), "%Y", c->xauth_identity); - escape_metachar(xauth_id_str, secure_xauth_id_str, - sizeof(secure_xauth_id_str)); - snprintf(xauth_id_str, sizeof(xauth_id_str), "PLUTO_XAUTH_ID='%s' ", - secure_xauth_id_str); - } - - addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str)); - snprintf(peerid_str, sizeof(peerid_str), "%Y", sr->that.id); - escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str)); - subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str)); - networkof(&sr->that.client, &ta); - addrtot(&ta, 0, peerclientnet_str, sizeof(peerclientnet_str)); - maskof(&sr->that.client, &ta); - addrtot(&ta, 0, peerclientmask_str, sizeof(peerclientmask_str)); - - for (p = pubkeys; p != NULL; p = p->next) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - int pathlen; - - if (type == KEY_RSA && - sr->that.id->equals(sr->that.id, key->id) && - trusted_ca(key->issuer, sr->that.ca, &pathlen)) - { - if (key->issuer) - { - snprintf(peerca_str, BUF_LEN, "%Y", key->issuer); - escape_metachar(peerca_str, secure_peerca_str, BUF_LEN); - } - else - { - secure_peerca_str[0] = '\0'; - } - break; - } - } - - if (-1 == snprintf(cmd, sizeof(cmd) - , "2>&1 " /* capture stderr along with stdout */ - "PLUTO_VERSION='1.1' " /* change VERSION when interface spec changes */ - "PLUTO_VERB='%s%s' " - "PLUTO_CONNECTION='%s' " - "%s" /* optional PLUTO_NEXT_HOP */ - "PLUTO_INTERFACE='%s' " - "%s" /* optional PLUTO_HOST_ACCESS */ - "PLUTO_REQID='%u' " - "PLUTO_ME='%s' " - "PLUTO_MY_ID='%s' " - "PLUTO_MY_CLIENT='%s' " - "PLUTO_MY_CLIENT_NET='%s' " - "PLUTO_MY_CLIENT_MASK='%s' " - "PLUTO_MY_PORT='%u' " - "PLUTO_MY_PROTOCOL='%u' " - "PLUTO_PEER='%s' " - "PLUTO_PEER_ID='%s' " - "PLUTO_PEER_CLIENT='%s' " - "PLUTO_PEER_CLIENT_NET='%s' " - "PLUTO_PEER_CLIENT_MASK='%s' " - "PLUTO_PEER_PORT='%u' " - "PLUTO_PEER_PROTOCOL='%u' " - "PLUTO_PEER_CA='%s' " - "%s" /* optional PLUTO_MY_SRCIP */ - "%s" /* optional PLUTO_XAUTH_ID */ - "%s" /* optional PLUTO_MARK_IN */ - "%s" /* optional PLUTO_MARK_OUT */ - "%s" /* optional PLUTO_UDP_ENC */ - "%s" /* actual script */ - , verb, verb_suffix - , c->name - , nexthop_str - , c->interface->vname - , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : "" - , sr->reqid - , me_str - , secure_myid_str - , myclient_str - , myclientnet_str - , myclientmask_str - , sr->this.port - , sr->this.protocol - , peer_str - , secure_peerid_str - , peerclient_str - , peerclientnet_str - , peerclientmask_str - , sr->that.port - , sr->that.protocol - , secure_peerca_str - , srcip_str - , xauth_id_str - , mark_in - , mark_out - , udp_encap - , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown)) - { - loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix); - return FALSE; - } - } - - DBG(DBG_CONTROL, DBG_log("executing %s%s: %s" - , verb, verb_suffix, cmd)); - - /* invoke the script, catching stderr and stdout - * It may be of concern that some file descriptors will - * be inherited. For the ones under our control, we - * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. - * Any used by library routines (perhaps the resolver or syslog) - * will remain. - */ - FILE *f = popen(cmd, "r"); - - if (f == NULL) - { - loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); - return FALSE; - } - - /* log any output */ - for (;;) - { - /* if response doesn't fit in this buffer, it will be folded */ - char resp[256]; - - if (fgets(resp, sizeof(resp), f) == NULL) - { - if (ferror(f)) - { - log_errno((e, "fgets failed on output of %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else - { - passert(feof(f)); - break; - } - } - else - { - char *e = resp + strlen(resp); - - if (e > resp && e[-1] == '\n') - e[-1] = '\0'; /* trim trailing '\n' */ - plog("%s%s output: %s", verb, verb_suffix, resp); - } - } - - /* report on and react to return code */ - { - int r = pclose(f); - - if (r == -1) - { - log_errno((e, "pclose failed for %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else if (WIFEXITED(r)) - { - if (WEXITSTATUS(r) != 0) - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d" - , verb, verb_suffix, WEXITSTATUS(r)); - return FALSE; - } - } - else if (WIFSIGNALED(r)) - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d" - , verb, verb_suffix, WTERMSIG(r)); - return FALSE; - } - else - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d" - , verb, verb_suffix, r); - return FALSE; - } - } - return TRUE; -} - -/* Check that we can route (and eroute). Diagnose if we cannot. */ - -enum routability { - route_impossible = 0, - route_easy = 1, - route_nearconflict = 2, - route_farconflict = 3 -}; - -static enum routability could_route(connection_t *c) -{ - struct spd_route *esr, *rosr; - connection_t *ero /* who, if anyone, owns our eroute? */ - , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */ - - /* it makes no sense to route a connection that is ISAKMP-only */ - if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) - { - loglog(RC_ROUTE, "cannot route an ISAKMP-only connection"); - return route_impossible; - } - - /* if this is a Road Warrior template, we cannot route. - * Opportunistic template is OK. - */ - if (c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO)) - { - loglog(RC_ROUTE, "cannot route Road Warrior template"); - return route_impossible; - } - - /* if we don't know nexthop, we cannot route */ - if (isanyaddr(&c->spd.this.host_nexthop)) - { - loglog(RC_ROUTE, "cannot route connection without knowing our nexthop"); - return route_impossible; - } - - /* if routing would affect IKE messages, reject */ - if (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT - && c->spd.this.host_port != IKE_UDP_PORT - && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client)) - { - loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client"); - return route_impossible; - } - - /* If there is already a route for peer's client subnet - * and it disagrees about interface or nexthop, we cannot steal it. - * Note: if this connection is already routed (perhaps for another - * state object), the route will agree. - * This is as it should be -- it will arise during rekeying. - */ - if (ro != NULL && !routes_agree(ro, c)) - { - loglog(RC_LOG_SERIOUS, "cannot route -- route already in use for \"%s\"" - , ro->name); - return route_impossible; /* another connection already - using the eroute */ - } - - /* if there is an eroute for another connection, there is a problem */ - if (ero != NULL && ero != c) - { - connection_t *ero2, *ero_top; - connection_t *inside, *outside; - - /* - * note, wavesec (PERMANENT) goes *outside* and - * OE goes *inside* (TEMPLATE) - */ - inside = NULL; - outside= NULL; - if (ero->kind == CK_PERMANENT - && c->kind == CK_TEMPLATE) - { - outside = ero; - inside = c; - } - else if (c->kind == CK_PERMANENT - && ero->kind == CK_TEMPLATE) - { - outside = c; - inside = ero; - } - - /* okay, check again, with correct order */ - if (outside && outside->kind == CK_PERMANENT - && inside && inside->kind == CK_TEMPLATE) - { - char inst[CONN_INST_BUF]; - - /* this is a co-terminal attempt of the "near" kind. */ - /* when chaining, we chain from inside to outside */ - - /* XXX permit multiple deep connections? */ - passert(inside->policy_next == NULL); - - inside->policy_next = outside; - - /* since we are going to steal the eroute from the secondary - * policy, we need to make sure that it no longer thinks that - * it owns the eroute. - */ - outside->spd.eroute_owner = SOS_NOBODY; - outside->spd.routing = RT_UNROUTED_KEYED; - - /* set the priority of the new eroute owner to be higher - * than that of the current eroute owner - */ - inside->prio = outside->prio + 1; - - fmt_conn_instance(inside, inst); - - loglog(RC_LOG_SERIOUS - , "conflict on eroute (%s), switching eroute to %s and linking %s" - , inst, inside->name, outside->name); - - return route_nearconflict; - } - - /* look along the chain of policies for one with the same name */ - ero_top = ero; - - for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) - { - if (ero2->kind == CK_TEMPLATE - && streq(ero2->name, c->name)) - break; - } - - /* If we fell of the end of the list, then we found no TEMPLATE - * so there must be a conflict that we can't resolve. - * As the names are not equal, then we aren't replacing/rekeying. - */ - if (ero2 == NULL) - { - char inst[CONN_INST_BUF]; - - fmt_conn_instance(ero, inst); - - loglog(RC_LOG_SERIOUS - , "cannot install eroute -- it is in use for \"%s\"%s #%lu" - , ero->name, inst, esr->eroute_owner); - return route_impossible; - } - } - return route_easy; -} - -bool trap_connection(connection_t *c) -{ - switch (could_route(c)) - { - case route_impossible: - return FALSE; - - case route_nearconflict: - case route_easy: - /* RT_ROUTED_TUNNEL is treated specially: we don't override - * because we don't want to lose track of the IPSEC_SAs etc. - */ - if (c->spd.routing < RT_ROUTED_TUNNEL) - { - return route_and_eroute(c, &c->spd, NULL); - } - return TRUE; - - case route_farconflict: - return FALSE; - } - - return FALSE; -} - -/** - * Delete any eroute for a connection and unroute it if route isn't shared - */ -void unroute_connection(connection_t *c) -{ - struct spd_route *sr; - enum routing_t cr; - - for (sr = &c->spd; sr; sr = sr->next) - { - cr = sr->routing; - - if (erouted(cr)) - { - /* cannot handle a live one */ - passert(sr->routing != RT_ROUTED_TUNNEL); - shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete"); - } - - sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */ - - /* only unroute if no other connection shares it */ - if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL) - { - (void) do_command(c, sr, NULL, "unroute"); - } - } -} - - -static void set_text_said(char *text_said, const ip_address *dst, - ipsec_spi_t spi, int proto) -{ - ip_said said; - - initsaid(dst, spi, proto, &said); - satot(&said, 0, text_said, SATOT_BUF); -} - - -/** - * Setup an IPsec route entry. - * op is one of the ERO_* operators. - */ -static bool raw_eroute(const ip_address *this_host, - const ip_subnet *this_client, - const ip_address *that_host, - const ip_subnet *that_client, - mark_t mark, - ipsec_spi_t spi, - unsigned int proto, - unsigned int satype, - unsigned int transport_proto, - ipsec_sa_cfg_t *sa, - unsigned int op, - const char *opname USED_BY_DEBUG) -{ - traffic_selector_t *ts_src, *ts_dst; - host_t *host_src, *host_dst; - policy_type_t type = POLICY_IPSEC; - policy_dir_t dir = POLICY_OUT; - policy_priority_t priority = POLICY_PRIORITY_DEFAULT; - char text_said[SATOT_BUF]; - bool ok = TRUE, - deleting = (op & ERO_MASK) == ERO_DELETE, - replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT); - - set_text_said(text_said, that_host, spi, proto); - - DBG(DBG_CONTROL | DBG_KERNEL, - { - int sport = ntohs(portof(&this_client->addr)); - int dport = ntohs(portof(&that_client->addr)); - char mybuf[SUBNETTOT_BUF]; - char peerbuf[SUBNETTOT_BUF]; - - subnettot(this_client, 0, mybuf, sizeof(mybuf)); - subnettot(that_client, 0, peerbuf, sizeof(peerbuf)); - DBG_log("%s eroute %s:%d -> %s:%d => %s:%d" - , opname, mybuf, sport, peerbuf, dport - , text_said, transport_proto); - }); - - if (satype == SADB_X_SATYPE_INT) - { - switch (ntohl(spi)) - { - case SPI_PASS: - type = POLICY_PASS; - break; - case SPI_DROP: - case SPI_REJECT: - type = POLICY_DROP; - break; - case SPI_TRAP: - case SPI_TRAPSUBNET: - case SPI_HOLD: - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - return TRUE; - } - priority = POLICY_PRIORITY_ROUTED; - break; - } - } - - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - dir = POLICY_IN; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)this_host); - host_dst = host_create_from_sockaddr((sockaddr_t*)that_host); - ts_src = traffic_selector_from_subnet(this_client, transport_proto); - ts_dst = traffic_selector_from_subnet(that_client, transport_proto); - - if (deleting || replacing) - { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - ts_src, ts_dst, dir, sa->reqid, mark, priority); - } - - if (!deleting) - { - ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, - host_src, host_dst, ts_src, ts_dst, dir, type, sa, - mark, priority) == SUCCESS; - } - - if (dir == POLICY_IN) - { /* handle forward policy */ - dir = POLICY_FWD; - if (deleting || replacing) - { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - ts_src, ts_dst, dir, sa->reqid, mark, priority); - } - - if (!deleting && ok && - (sa->mode == MODE_TUNNEL || satype == SADB_X_SATYPE_INT)) - { - ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, - host_src, host_dst, ts_src, ts_dst, dir, type, sa, - mark, priority) == SUCCESS; - } - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - ts_src->destroy(ts_src); - ts_dst->destroy(ts_dst); - - return ok; -} - -static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, - unsigned int proto, unsigned int satype, - ipsec_sa_cfg_t *sa, unsigned int op, - const char *opname) -{ - const ip_address *peer = &sr->that.host_addr; - char buf2[256]; - bool ok; - - snprintf(buf2, sizeof(buf2) - , "eroute_connection %s", opname); - - if (proto == SA_INT) - { - peer = aftoinfo(addrtypeof(peer))->any; - } - ok = raw_eroute(peer, &sr->that.client, - &sr->this.host_addr, &sr->this.client, sr->mark_in, - spi, proto, satype, sr->this.protocol, - sa, op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), buf2); - return raw_eroute(&sr->this.host_addr, &sr->this.client, peer, - &sr->that.client, sr->mark_out, spi, proto, satype, - sr->this.protocol, sa, op, buf2) && ok; -} - -/* assign a bare hold to a connection */ - -bool assign_hold(connection_t *c USED_BY_DEBUG, struct spd_route *sr, - int transport_proto, - const ip_address *src, - const ip_address *dst) -{ - /* either the automatically installed %hold eroute is broad enough - * or we try to add a broader one and delete the automatic one. - * Beware: this %hold might be already handled, but still squeak - * through because of a race. - */ - enum routing_t ro = sr->routing /* routing, old */ - , rn = ro; /* routing, new */ - - passert(LHAS(LELEM(CK_PERMANENT) | LELEM(CK_INSTANCE), c->kind)); - /* figure out what routing should become */ - switch (ro) - { - case RT_UNROUTED: - rn = RT_UNROUTED_HOLD; - break; - case RT_ROUTED_PROSPECTIVE: - rn = RT_ROUTED_HOLD; - break; - default: - /* no change: this %hold is old news and should just be deleted */ - break; - } - - /* We need a broad %hold - * First we ensure that there is a broad %hold. - * There may already be one (race condition): no need to create one. - * There may already be a %trap: replace it. - * There may not be any broad eroute: add %hold. - */ - if (rn != ro) - { - if (erouted(ro) - ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, ERO_REPLACE, - "replace %trap with broad %hold") - : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, ERO_ADD, "add broad %hold")) - { - return FALSE; - } - } - sr->routing = rn; - return TRUE; -} - -/* install or remove eroute for SA Group */ -static bool sag_eroute(struct state *st, struct spd_route *sr, - unsigned op, const char *opname) -{ - u_int inner_proto, inner_satype; - ipsec_spi_t inner_spi = 0; - ipsec_sa_cfg_t sa = { - .mode = MODE_TRANSPORT, - }; - bool tunnel = FALSE; - - if (st->st_ah.present) - { - inner_spi = st->st_ah.attrs.spi; - inner_proto = SA_AH; - inner_satype = SADB_SATYPE_AH; - sa.ah.use = TRUE; - sa.ah.spi = inner_spi; - tunnel |= st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (st->st_esp.present) - { - inner_spi = st->st_esp.attrs.spi; - inner_proto = SA_ESP; - inner_satype = SADB_SATYPE_ESP; - sa.esp.use = TRUE; - sa.esp.spi = inner_spi; - tunnel |= st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (st->st_ipcomp.present) - { - inner_spi = st->st_ipcomp.attrs.spi; - inner_proto = SA_COMP; - inner_satype = SADB_X_SATYPE_COMP; - sa.ipcomp.transform = st->st_ipcomp.attrs.transid; - sa.ipcomp.cpi = htons(ntohl(inner_spi)); - tunnel |= st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (!sa.ah.use && !sa.esp.use && !sa.ipcomp.transform) - { - impossible(); /* no transform at all! */ - } - - if (tunnel) - { - inner_spi = st->st_tunnel_out_spi; - inner_proto = SA_IPIP; - inner_satype = SADB_X_SATYPE_IPIP; - sa.mode = MODE_TUNNEL; - } - - sa.reqid = sr->reqid; - - return eroute_connection(sr, inner_spi, inner_proto, inner_satype, - &sa, op, opname); -} - -/* compute a (host-order!) SPI to implement the policy in connection c */ -ipsec_spi_t -shunt_policy_spi(connection_t *c, bool prospective) -{ - /* note: these are in host order :-( */ - static const ipsec_spi_t shunt_spi[] = - { - SPI_TRAP, /* --initiateontraffic */ - SPI_PASS, /* --pass */ - SPI_DROP, /* --drop */ - SPI_REJECT, /* --reject */ - }; - - static const ipsec_spi_t fail_spi[] = - { - 0, /* --none*/ - SPI_PASS, /* --failpass */ - SPI_DROP, /* --faildrop */ - SPI_REJECT, /* --failreject */ - }; - - return prospective - ? shunt_spi[(c->policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT] - : fail_spi[(c->policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT]; -} - -/* Add/replace/delete a shunt eroute. - * Such an eroute determines the fate of packets without the use - * of any SAs. These are defaults, in effect. - * If a negotiation has not been attempted, use %trap. - * If negotiation has failed, the choice between %trap/%pass/%drop/%reject - * is specified in the policy of connection c. - */ -static bool shunt_eroute(connection_t *c, struct spd_route *sr, - enum routing_t rt_kind, - unsigned int op, const char *opname) -{ - /* We are constructing a special SAID for the eroute. - * The destination doesn't seem to matter, but the family does. - * The protocol is SA_INT -- mark this as shunt. - * The satype has no meaning, but is required for PF_KEY header! - * The SPI signifies the kind of shunt. - */ - ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE); - - if (spi == 0) - { - /* we're supposed to end up with no eroute: rejig op and opname */ - switch (op) - { - case ERO_REPLACE: - /* replace with nothing == delete */ - op = ERO_DELETE; - opname = "delete"; - break; - case ERO_ADD: - /* add nothing == do nothing */ - return TRUE; - case ERO_DELETE: - /* delete remains delete */ - break; - default: - bad_case(op); - } - } - if (sr->routing == RT_ROUTED_ECLIPSED && c->kind == CK_TEMPLATE) - { - /* We think that we have an eroute, but we don't. - * Adjust the request and account for eclipses. - */ - passert(eclipsable(sr)); - switch (op) - { - case ERO_REPLACE: - /* really an add */ - op = ERO_ADD; - opname = "replace eclipsed"; - eclipse_count--; - break; - case ERO_DELETE: - /* delete unnecessary: we don't actually have an eroute */ - eclipse_count--; - return TRUE; - case ERO_ADD: - default: - bad_case(op); - } - } - else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr)) - { - /* maybe we are uneclipsing something */ - struct spd_route *esr; - connection_t *ue = eclipsed(c, &esr); - - if (ue != NULL) - { - esr->routing = RT_ROUTED_PROSPECTIVE; - return shunt_eroute(ue, esr - , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed"); - } - } - - return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, op, opname); -} - -static bool setup_half_ipsec_sa(struct state *st, bool inbound) -{ - host_t *host_src, *host_dst; - connection_t *c = st->st_connection; - struct end *src, *dst; - ipsec_mode_t mode = MODE_TRANSPORT; - ipsec_sa_cfg_t sa = { .mode = 0 }; - lifetime_cfg_t lt_none = { .time = { .rekey = 0 } }; - mark_t mark; - bool ok = TRUE; - /* SPIs, saved for undoing, if necessary */ - struct kernel_sa said[EM_MAXRELSPIS], *said_next = said; - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - mode = MODE_TUNNEL; - } - - sa.mode = mode; - sa.reqid = c->spd.reqid; - - memset(said, 0, sizeof(said)); - - /* set up IPCOMP SA, if any */ - - if (st->st_ipcomp.present) - { - ipsec_spi_t ipcomp_spi = inbound ? st->st_ipcomp.our_spi - : st->st_ipcomp.attrs.spi; - - switch (st->st_ipcomp.attrs.transid) - { - case IPCOMP_DEFLATE: - break; - - default: - loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented", - enum_name(&ipcomp_transformid_names, - st->st_ipcomp.attrs.transid)); - goto fail; - } - - sa.ipcomp.cpi = htons(ntohl(ipcomp_spi)); - sa.ipcomp.transform = st->st_ipcomp.attrs.transid; - - said_next->spi = ipcomp_spi; - said_next->proto = IPPROTO_COMP; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, ipcomp_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, ENCR_UNDEFINED, chunk_empty, - AUTH_UNDEFINED, chunk_empty, mode, - st->st_ipcomp.attrs.transid, 0 /* cpi */, FALSE, FALSE, - inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - /* set up ESP SA, if any */ - - if (st->st_esp.present) - { - ipsec_spi_t esp_spi = inbound ? st->st_esp.our_spi - : st->st_esp.attrs.spi; - u_char *esp_dst_keymat = inbound ? st->st_esp.our_keymat - : st->st_esp.peer_keymat; - bool encap = st->nat_traversal & NAT_T_DETECTED; - encryption_algorithm_t enc_alg; - integrity_algorithm_t auth_alg; - const struct esp_info *ei; - chunk_t enc_key, auth_key; - u_int16_t key_len; - - if ((ei = kernel_alg_esp_info(st->st_esp.attrs.transid, - st->st_esp.attrs.auth)) == NULL) - { - loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s" - " not implemented yet", - enum_name(&esp_transform_names, st->st_esp.attrs.transid), - enum_name(&auth_alg_names, st->st_esp.attrs.auth)); - goto fail; - } - - key_len = st->st_esp.attrs.key_len / 8; - if (key_len) - { - /* XXX: must change to check valid _range_ key_len */ - if (key_len > ei->enckeylen) - { - loglog(RC_LOG_SERIOUS, "ESP transform %s: key_len=%d > %d", - enum_name(&esp_transform_names, st->st_esp.attrs.transid), - (int)key_len, (int)ei->enckeylen); - goto fail; - } - } - else - { - key_len = ei->enckeylen; - } - - switch (ei->transid) - { - case ESP_3DES: - /* 168 bits in kernel, need 192 bits for keymat_len */ - if (key_len == 21) - { - key_len = 24; - } - break; - case ESP_DES: - /* 56 bits in kernel, need 64 bits for keymat_len */ - if (key_len == 7) - { - key_len = 8; - } - break; - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - key_len += 3; - break; - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_CTR: - case ESP_AES_GMAC: - key_len += 4; - break; - default: - break; - } - - if (encap) - { - host_src->set_port(host_src, src->host_port); - host_dst->set_port(host_dst, dst->host_port); - // st->nat_oa is currently unused - } - - /* divide up keying material */ - enc_alg = encryption_algorithm_from_esp(st->st_esp.attrs.transid); - enc_key.ptr = esp_dst_keymat; - enc_key.len = key_len; - auth_alg = integrity_algorithm_from_esp(st->st_esp.attrs.auth); - auth_alg = auth_alg ? : AUTH_UNDEFINED; - auth_key.ptr = esp_dst_keymat + key_len; - auth_key.len = ei->authkeylen; - - sa.esp.use = TRUE; - sa.esp.spi = esp_spi; - - said_next->spi = esp_spi; - said_next->proto = IPPROTO_ESP; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, esp_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, enc_alg, enc_key, - auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, - encap, FALSE, inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - /* set up AH SA, if any */ - - if (st->st_ah.present) - { - ipsec_spi_t ah_spi = inbound ? st->st_ah.our_spi - : st->st_ah.attrs.spi; - u_char *ah_dst_keymat = inbound ? st->st_ah.our_keymat - : st->st_ah.peer_keymat; - integrity_algorithm_t auth_alg; - chunk_t auth_key; - - auth_alg = integrity_algorithm_from_esp(st->st_ah.attrs.auth); - auth_key.ptr = ah_dst_keymat; - auth_key.len = st->st_ah.keymat_len; - - sa.ah.use = TRUE; - sa.ah.spi = ah_spi; - - said_next->spi = ah_spi; - said_next->proto = IPPROTO_AH; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, ah_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, ENCR_UNDEFINED, chunk_empty, - auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, - FALSE, FALSE, inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - goto cleanup; - -fail: - /* undo the done SPIs */ - while (said_next-- != said) - { - hydra->kernel_interface->del_sa(hydra->kernel_interface, host_src, - host_dst, said_next->spi, - said_next->proto, 0 /* cpi */, - mark); - } - ok = FALSE; - -cleanup: - host_src->destroy(host_src); - host_dst->destroy(host_dst); - return ok; -} - -static bool teardown_half_ipsec_sa(struct state *st, bool inbound) -{ - connection_t *c = st->st_connection; - const struct end *src, *dst; - host_t *host_src, *host_dst; - ipsec_spi_t spi; - mark_t mark; - bool result = TRUE; - - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - if (st->st_ah.present) - { - spi = inbound ? st->st_ah.our_spi : st->st_ah.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_AH, - 0 /* cpi */, mark) == SUCCESS; - } - - if (st->st_esp.present) - { - spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_ESP, - 0 /* cpi */, mark) == SUCCESS; - } - - if (st->st_ipcomp.present) - { - spi = inbound ? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_COMP, - 0 /* cpi */, mark) == SUCCESS; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return result; -} - -/* - * get information about a given sa - */ -bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time) -{ - connection_t *c = st->st_connection; - traffic_selector_t *ts_src = NULL, *ts_dst = NULL; - host_t *host_src = NULL, *host_dst = NULL; - const struct end *src, *dst; - ipsec_spi_t spi; - mark_t mark; - u_int64_t bytes_kernel = 0; - bool result = FALSE; - - *use_time = UNDEFINED_TIME; - - if (!st->st_esp.present) - { - goto failed; - } - - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - spi = st->st_esp.our_spi; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - spi = st->st_esp.attrs.spi; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - switch(hydra->kernel_interface->query_sa(hydra->kernel_interface, host_src, - host_dst, spi, IPPROTO_ESP, - mark, &bytes_kernel)) - { - case FAILED: - goto failed; - case SUCCESS: - *bytes = bytes_kernel; - break; - case NOT_SUPPORTED: - default: - break; - } - - if (st->st_serialno == c->spd.eroute_owner) - { - u_int32_t time_kernel; - - ts_src = traffic_selector_from_subnet(&src->client, src->protocol); - ts_dst = traffic_selector_from_subnet(&dst->client, dst->protocol); - - if (hydra->kernel_interface->query_policy(hydra->kernel_interface, - ts_src, ts_dst, inbound ? POLICY_IN : POLICY_OUT, - mark, &time_kernel) != SUCCESS) - { - goto failed; - } - *use_time = time_kernel; - - if (inbound && - st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - if (hydra->kernel_interface->query_policy(hydra->kernel_interface, - ts_src, ts_dst, POLICY_FWD, mark, - &time_kernel) != SUCCESS) - { - goto failed; - } - *use_time = max(*use_time, time_kernel); - } - } - - result = TRUE; - -failed: - DESTROY_IF(host_src); - DESTROY_IF(host_dst); - DESTROY_IF(ts_src); - DESTROY_IF(ts_dst); - return result; -} - -/** - * Handler for kernel events (called by thread-pool thread) - */ -kernel_listener_t *kernel_handler; - -/** - * Data for acquire events - */ -typedef struct { - /** Subnets */ - ip_subnet src, dst; - /** Transport protocol */ - int proto; -} acquire_data_t; - -/** - * Callback for acquire events (called by main thread) - */ -void handle_acquire(acquire_data_t *this) -{ - record_and_initiate_opportunistic(&this->src, &this->dst, this->proto, - "%acquire"); -} - -METHOD(kernel_listener_t, acquire, bool, - kernel_listener_t *this, u_int32_t reqid, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts) -{ - if (src_ts && dst_ts) - { - acquire_data_t *data; - DBG(DBG_CONTROL, - DBG_log("creating acquire event for policy %R === %R " - "with reqid {%u}", src_ts, dst_ts, reqid)); - INIT(data, - .src = subnet_from_traffic_selector(src_ts), - .dst = subnet_from_traffic_selector(dst_ts), - .proto = src_ts->get_protocol(src_ts), - ); - pluto->events->queue(pluto->events, (void*)handle_acquire, data, free); - } - else - { - DBG(DBG_CONTROL, - DBG_log("ignoring acquire without traffic selectors for policy " - "with reqid {%u}", reqid)); - } - DESTROY_IF(src_ts); - DESTROY_IF(dst_ts); - return TRUE; -} - -/** - * Data for mapping events - */ -typedef struct { - /** reqid, spi of affected SA */ - u_int32_t reqid, spi; - /** new endpont */ - ip_address new_end; -} mapping_data_t; - -/** - * Callback for mapping events (called by main thread) - */ -void handle_mapping(mapping_data_t *this) -{ - process_nat_t_new_mapping(this->reqid, this->spi, &this->new_end); -} - - -METHOD(kernel_listener_t, mapping, bool, - kernel_listener_t *this, u_int32_t reqid, u_int32_t spi, host_t *remote) -{ - mapping_data_t *data; - DBG(DBG_CONTROL, - DBG_log("creating mapping event for SA with SPI %.8x and reqid {%u}", - spi, reqid)); - INIT(data, - .reqid = reqid, - .spi = spi, - .new_end = *(ip_address*)remote->get_sockaddr(remote), - ); - pluto->events->queue(pluto->events, (void*)handle_mapping, data, free); - return TRUE; -} - -void init_kernel(void) -{ - /* register SA types that we can negotiate */ - can_do_IPcomp = FALSE; /* until we get a response from the kernel */ - pfkey_register(); - - INIT(kernel_handler, - .acquire = _acquire, - .mapping = _mapping, - ); - hydra->kernel_interface->add_listener(hydra->kernel_interface, - kernel_handler); -} - -void kernel_finalize() -{ - hydra->kernel_interface->remove_listener(hydra->kernel_interface, - kernel_handler); - free(kernel_handler); -} - -/* Note: install_inbound_ipsec_sa is only used by the Responder. - * The Responder will subsequently use install_ipsec_sa for the outbound. - * The Initiator uses install_ipsec_sa to install both at once. - */ -bool install_inbound_ipsec_sa(struct state *st) -{ - connection_t *const c = st->st_connection; - - /* If our peer has a fixed-address client, check if we already - * have a route for that client that conflicts. We will take this - * as proof that that route and the connections using it are - * obsolete and should be eliminated. Interestingly, this is - * the only case in which we can tell that a connection is obsolete. - */ - passert(c->kind == CK_PERMANENT || c->kind == CK_INSTANCE); - if (c->spd.that.has_client) - { - for (;;) - { - struct spd_route *esr; - connection_t *o = route_owner(c, &esr, NULL, NULL); - - if (o == NULL) - { - break; /* nobody has a route */ - } - - /* note: we ignore the client addresses at this end */ - if (sameaddr(&o->spd.that.host_addr, &c->spd.that.host_addr) && - o->interface == c->interface) - { - break; /* existing route is compatible */ - } - - if (o->kind == CK_TEMPLATE && streq(o->name, c->name)) - { - break; /* ??? is this good enough?? */ - } - - loglog(RC_LOG_SERIOUS, "route to peer's client conflicts with \"%s\" %s; releasing old connection to free the route" - , o->name, ip_str(&o->spd.that.host_addr)); - release_connection(o, FALSE); - } - } - - DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa() checking if we can route")); - /* check that we will be able to route and eroute */ - switch (could_route(c)) - { - case route_easy: - case route_nearconflict: - break; - default: - return FALSE; - } - - /* (attempt to) actually set up the SAs */ - return setup_half_ipsec_sa(st, TRUE); -} - -/* Install a route and then a prospective shunt eroute or an SA group eroute. - * Assumption: could_route gave a go-ahead. - * Any SA Group must have already been created. - * On failure, steps will be unwound. - */ -bool route_and_eroute(connection_t *c, struct spd_route *sr, struct state *st) -{ - struct spd_route *esr; - struct spd_route *rosr; - connection_t *ero /* who, if anyone, owns our eroute? */ - , *ro = route_owner(c, &rosr, &ero, &esr); - bool eroute_installed = FALSE - , firewall_notified = FALSE - , route_installed = FALSE; - - connection_t *ero_top; - - DBG(DBG_CONTROLMORE, - DBG_log("route_and_eroute with c: %s (next: %s) ero:%s esr:{%p} ro:%s rosr:{%p} and state: %lu" - , c->name - , (c->policy_next ? c->policy_next->name : "none") - , ero ? ero->name : "null" - , esr - , ro ? ro->name : "null" - , rosr - , st ? st->st_serialno : 0)); - - /* look along the chain of policies for one with the same name */ - ero_top = ero; - -#if 0 - /* XXX - mcr this made sense before, and likely will make sense - * again, so I'l leaving this to remind me what is up */ - if (ero!= NULL && ero->routing == RT_UNROUTED_KEYED) - ero = NULL; - - for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) - if ((ero2->kind == CK_TEMPLATE || ero2->kind==CK_SECONDARY) - && streq(ero2->name, c->name)) - break; -#endif - - /* install the eroute */ - - if (ero != NULL) - { - /* We're replacing an eroute */ - - /* if no state provided, then install a shunt for later */ - if (st == NULL) - { - eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE - , ERO_REPLACE, "replace"); - } - else - { - eroute_installed = sag_eroute(st, sr, ERO_REPLACE, "replace"); - } -#if 0 - /* XXX - MCR. I previously felt that this was a bogus check */ - if (ero != NULL && ero != c && esr != sr) - { - /* By elimination, we must be eclipsing ero. Check. */ - passert(ero->kind == CK_TEMPLATE && streq(ero->name, c->name)); - passert(LHAS(LELEM(RT_ROUTED_PROSPECTIVE) | LELEM(RT_ROUTED_ECLIPSED) - , esr->routing)); - passert(samesubnet(&esr->this.client, &sr->this.client) - && samesubnet(&esr->that.client, &sr->that.client)); - } -#endif - } - else - { - /* we're adding an eroute */ - - /* if no state provided, then install a shunt for later */ - if (st == NULL) - { - eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE - , ERO_ADD, "add"); - } - else - { - eroute_installed = sag_eroute(st, sr, ERO_ADD, "add"); - } - } - - /* notify the firewall of a new tunnel */ - - if (eroute_installed) - { - /* do we have to notify the firewall? Yes, if we are installing - * a tunnel eroute and the firewall wasn't notified - * for a previous tunnel with the same clients. Any Previous - * tunnel would have to be for our connection, so the actual - * test is simple. - */ - firewall_notified = st == NULL /* not a tunnel eroute */ - || sr->eroute_owner != SOS_NOBODY /* already notified */ - || do_command(c, sr, st, "up"); /* go ahead and notify */ - } - - /* install the route */ - - DBG(DBG_CONTROL, - DBG_log("route_and_eroute: firewall_notified: %s" - , firewall_notified ? "true" : "false")); - if (!firewall_notified) - { - /* we're in trouble -- don't do routing */ - } - else if (ro == NULL) - { - /* a new route: no deletion required, but preparation is */ - (void) do_command(c, sr, st, "prepare"); /* just in case; ignore failure */ - route_installed = do_command(c, sr, st, "route"); - } - else if (routed(sr->routing) || routes_agree(ro, c)) - { - route_installed = TRUE; /* nothing to be done */ - } - else - { - /* Some other connection must own the route - * and the route must disagree. But since could_route - * must have allowed our stealing it, we'll do so. - * - * A feature of LINUX allows us to install the new route - * before deleting the old if the nexthops differ. - * This reduces the "window of vulnerability" when packets - * might flow in the clear. - */ - if (sameaddr(&sr->this.host_nexthop, &esr->this.host_nexthop)) - { - (void) do_command(ro, sr, st, "unroute"); - route_installed = do_command(c, sr, st, "route"); - } - else - { - route_installed = do_command(c, sr, st, "route"); - (void) do_command(ro, sr, st, "unroute"); - } - - /* record unrouting */ - if (route_installed) - { - do { - passert(!erouted(rosr->routing)); - rosr->routing = RT_UNROUTED; - - /* no need to keep old value */ - ro = route_owner(c, &rosr, NULL, NULL); - } while (ro != NULL); - } - } - - /* all done -- clean up */ - if (route_installed) - { - /* Success! */ - - if (ero != NULL && ero != c) - { - /* check if ero is an ancestor of c. */ - connection_t *ero2; - - for (ero2 = c; ero2 != NULL && ero2 != c; ero2 = ero2->policy_next) - ; - - if (ero2 == NULL) - { - /* By elimination, we must be eclipsing ero. Checked above. */ - if (ero->spd.routing != RT_ROUTED_ECLIPSED) - { - ero->spd.routing = RT_ROUTED_ECLIPSED; - eclipse_count++; - } - } - } - - if (st == NULL) - { - passert(sr->eroute_owner == SOS_NOBODY); - sr->routing = RT_ROUTED_PROSPECTIVE; - } - else - { - char cib[CONN_INST_BUF]; - sr->routing = RT_ROUTED_TUNNEL; - - DBG(DBG_CONTROL, - DBG_log("route_and_eroute: instance \"%s\"%s, setting eroute_owner {spd=%p,sr=%p} to #%ld (was #%ld) (newest_ipsec_sa=#%ld)" - , st->st_connection->name - , (fmt_conn_instance(st->st_connection, cib), cib) - , &st->st_connection->spd, sr - , st->st_serialno - , sr->eroute_owner - , st->st_connection->newest_ipsec_sa)); - sr->eroute_owner = st->st_serialno; - } - - return TRUE; - } - else - { - /* Failure! Unwind our work. */ - if (firewall_notified && sr->eroute_owner == SOS_NOBODY) - (void) do_command(c, sr, st, "down"); - - if (eroute_installed) - { - /* Restore original eroute, if we can. - * Since there is nothing much to be done if the restoration - * fails, ignore success or failure. - */ - if (ero != NULL) - { - /* restore ero's former glory */ - if (esr->eroute_owner == SOS_NOBODY) - { - /* note: normal or eclipse case */ - (void) shunt_eroute(ero, esr - , esr->routing, ERO_REPLACE, "restore"); - } - else - { - /* Try to find state that owned eroute. - * Don't do anything if it cannot be found. - * This case isn't likely since we don't run - * the updown script when replacing a SA group - * with its successor (for the same conn). - */ - struct state *ost = state_with_serialno(esr->eroute_owner); - - if (ost != NULL) - (void) sag_eroute(ost, esr, ERO_REPLACE, "restore"); - } - } - else - { - /* there was no previous eroute: delete whatever we installed */ - if (st == NULL) - { - (void) shunt_eroute(c, sr, sr->routing, ERO_DELETE, "delete"); - } - else - { - (void) sag_eroute(st, sr, ERO_DELETE, "delete"); - } - } - } - - return FALSE; - } -} - -bool install_ipsec_sa(struct state *st, bool inbound_also) -{ - struct spd_route *sr; - - DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() for #%ld: %s" - , st->st_serialno - , inbound_also? - "inbound and outbound" : "outbound only")); - - switch (could_route(st->st_connection)) - { - case route_easy: - case route_nearconflict: - break; - default: - return FALSE; - } - - /* (attempt to) actually set up the SA group */ - if ((inbound_also && !setup_half_ipsec_sa(st, TRUE)) || - !setup_half_ipsec_sa(st, FALSE)) - { - return FALSE; - } - - for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next) - { - DBG(DBG_CONTROL, DBG_log("sr for #%ld: %s" - , st->st_serialno - , enum_name(&routing_story, sr->routing))); - - /* - * if the eroute owner is not us, then make it us. - * See test co-terminal-02, pluto-rekey-01, pluto-unit-02/oppo-twice - */ - pexpect(sr->eroute_owner == SOS_NOBODY - || sr->routing >= RT_ROUTED_TUNNEL); - - if (sr->eroute_owner != st->st_serialno - && sr->routing != RT_UNROUTED_KEYED) - { - if (!route_and_eroute(st->st_connection, sr, st)) - { - delete_ipsec_sa(st, FALSE); - /* XXX go and unroute any SRs that were successfully - * routed already. - */ - return FALSE; - } - } - } - - return TRUE; -} - -/* delete an IPSEC SA. - * we may not succeed, but we bull ahead anyway because - * we cannot do anything better by recognizing failure - */ -void delete_ipsec_sa(struct state *st, bool inbound_only) -{ - if (!inbound_only) - { - /* If the state is the eroute owner, we must adjust - * the routing for the connection. - */ - connection_t *c = st->st_connection; - struct spd_route *sr; - - passert(st->st_connection); - - for (sr = &c->spd; sr; sr = sr->next) - { - if (sr->eroute_owner == st->st_serialno - && sr->routing == RT_ROUTED_TUNNEL) - { - sr->eroute_owner = SOS_NOBODY; - - /* Routing should become RT_ROUTED_FAILURE, - * but if POLICY_FAIL_NONE, then we just go - * right back to RT_ROUTED_PROSPECTIVE as if no - * failure happened. - */ - sr->routing = (c->policy & POLICY_FAIL_MASK) == POLICY_FAIL_NONE - ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE; - - (void) do_command(c, sr, st, "down"); - if ((c->policy & POLICY_DONT_REKEY) && c->kind == CK_INSTANCE) - { - /* in this special case, even if the connection - * is still alive (due to an ISAKMP SA), - * we get rid of routing. - * Even though there is still an eroute, the c->routing - * setting will convince unroute_connection to delete it. - * unroute_connection would be upset if c->routing == RT_ROUTED_TUNNEL - */ - unroute_connection(c); - } - else - { - (void) shunt_eroute(c, sr, sr->routing, ERO_REPLACE, "replace with shunt"); - } - } - } - (void) teardown_half_ipsec_sa(st, FALSE); - } - (void) teardown_half_ipsec_sa(st, TRUE); -} - -static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound) -{ - connection_t *c = st->st_connection; - host_t *host_src, *host_dst, *new_src, *new_dst; - ipsec_spi_t spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; - struct end *src = inbound ? &c->spd.that : &c->spd.this, - *dst = inbound ? &c->spd.this : &c->spd.that; - mark_t mark = inbound ? c->spd.mark_in : c->spd.mark_out; - bool result; - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - new_src = host_src->clone(host_src); - new_dst = host_dst->clone(host_dst); - new_src->set_port(new_src, src->host_port); - new_dst->set_port(new_dst, dst->host_port); - - result = hydra->kernel_interface->update_sa(hydra->kernel_interface, - spi, IPPROTO_ESP, 0 /* cpi */, host_src, host_dst, - new_src, new_dst, TRUE /* encap */, TRUE /* new_encap */, - mark) == SUCCESS; - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - new_src->destroy(new_src); - new_dst->destroy(new_dst); - - return result; -} - -bool update_ipsec_sa (struct state *st) -{ - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (st->st_esp.present && ( - (!update_nat_t_ipsec_esp_sa (st, TRUE)) || - (!update_nat_t_ipsec_esp_sa (st, FALSE)))) - { - return FALSE; - } - } - else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (st->st_esp.present && !update_nat_t_ipsec_esp_sa (st, FALSE)) - { - return FALSE; - } - } - else - { - DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__, st->st_state); - return FALSE; - } - return TRUE; -} - -/* Check if there was traffic on given SA during the last idle_max - * seconds. If TRUE, the SA was idle and DPD exchange should be performed. - * If FALSE, DPD is not necessary. We also return TRUE for errors, as they - * could mean that the SA is broken and needs to be replace anyway. - */ -bool was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time) -{ - time_t use_time; - u_int bytes; - int ret = TRUE; - - passert(st != NULL); - - if (get_sa_info(st, TRUE, &bytes, &use_time) && use_time != UNDEFINED_TIME) - { - *idle_time = time_monotonic(NULL) - use_time; - ret = *idle_time >= idle_max; - } - - return ret; -} diff --git a/src/pluto/kernel.h b/src/pluto/kernel.h deleted file mode 100644 index 1fa11c50e..000000000 --- a/src/pluto/kernel.h +++ /dev/null @@ -1,118 +0,0 @@ -/* declarations of routines that interface with the kernel's IPsec mechanism - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "connections.h" - -extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */ - -/* Declare eroute things early enough for uses. - * - * Flags are encoded above the low-order byte of verbs. - * "real" eroutes are only outbound. Inbound eroutes don't exist, - * but an addflow with an INBOUND flag allows IPIP tunnels to be - * limited to appropriate source and destination addresses. - */ - -#define ERO_MASK 0xFF -#define ERO_FLAG_SHIFT 8 - -#define ERO_DELETE SADB_X_DELFLOW -#define ERO_ADD SADB_X_ADDFLOW -#define ERO_REPLACE (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT)) - -struct pfkey_proto_info { - int proto; - int encapsulation; - unsigned reqid; -}; -struct sadb_msg; - -struct kernel_sa { - const ip_address *src; - const ip_address *dst; - - const ip_subnet *src_client; - const ip_subnet *dst_client; - - ipsec_spi_t spi; - unsigned proto; - unsigned satype; - unsigned transport_proto; - unsigned replay_window; - unsigned reqid; - - unsigned authalg; - unsigned authkeylen; - char *authkey; - - unsigned encalg; - unsigned enckeylen; - char *enckey; - - unsigned compalg; - - int encapsulation; - - u_int16_t natt_sport, natt_dport; - u_int8_t transid, natt_type; - ip_address *natt_oa; - - const char *text_said; -}; - -/* A netlink header defines EM_MAXRELSPIS, the max number of SAs in a group. - * Is there a PF_KEY equivalent? - */ -#ifndef EM_MAXRELSPIS -# define EM_MAXRELSPIS 4 /* AH ESP IPCOMP IPIP */ -#endif - -extern void record_and_initiate_opportunistic(const ip_subnet * - , const ip_subnet * - , int transport_proto - , const char *why); - -extern void init_kernel(void); -extern void kernel_finalize(void); - -extern bool trap_connection(struct connection *c); -extern void unroute_connection(struct connection *c); - -extern bool assign_hold(struct connection *c - , struct spd_route *sr - , int transport_proto - , const ip_address *src, const ip_address *dst); - -extern ipsec_spi_t shunt_policy_spi(struct connection *c, bool prospective); - - -struct state; /* forward declaration of tag */ -extern ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid - , int proto - , struct spd_route *sr - , bool tunnel_mode); -extern ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel_mode); - -extern bool install_inbound_ipsec_sa(struct state *st); -extern bool install_ipsec_sa(struct state *st, bool inbound_also); -extern void delete_ipsec_sa(struct state *st, bool inbound_only); -extern bool route_and_eroute(struct connection *c - , struct spd_route *sr - , struct state *st); -extern bool was_eroute_idle(struct state *st, time_t idle_max - , time_t *idle_time); -extern bool get_sa_info(struct state *st, bool inbound, u_int *bytes - , time_t *use_time); - -extern bool update_ipsec_sa(struct state *st); diff --git a/src/pluto/kernel_alg.c b/src/pluto/kernel_alg.c deleted file mode 100644 index b4b18fd80..000000000 --- a/src/pluto/kernel_alg.c +++ /dev/null @@ -1,663 +0,0 @@ -/* Kernel runtime algorithm handling interface - * Copyright (C) JuanJo Ciarlante - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "packet.h" -#include "spdb.h" -#include "kernel.h" -#include "kernel_alg.h" -#include "alg_info.h" -#include "log.h" -#include "whack.h" -#include "db_ops.h" - -/* ALG storage */ -static struct sadb_alg esp_aalg[SADB_AALG_MAX+1]; -static struct sadb_alg esp_ealg[SADB_EALG_MAX+1]; -static int esp_ealg_num = 0; -static int esp_aalg_num = 0; - -#define ESP_EALG_PRESENT(algo) (((algo)<=SADB_EALG_MAX)&&(esp_ealg[(algo)].sadb_alg_id==(algo))) -#define ESP_EALG_FOR_EACH_UPDOWN(algo) \ - for (algo=SADB_EALG_MAX; algo >0 ; algo--) \ - if (ESP_EALG_PRESENT(algo)) -#define ESP_AALG_PRESENT(algo) ((algo<=SADB_AALG_MAX)&&(esp_aalg[(algo)].sadb_alg_id==(algo))) -#define ESP_AALG_FOR_EACH_UPDOWN(algo) \ - for (algo=SADB_AALG_MAX; algo >0 ; algo--) \ - if (ESP_AALG_PRESENT(algo)) - -static struct sadb_alg* sadb_alg_ptr (int satype, int exttype, int alg_id, - int rw) -{ - struct sadb_alg *alg_p = NULL; - - switch (exttype) - { - case SADB_EXT_SUPPORTED_AUTH: - if (alg_id > SADB_AALG_MAX) - return NULL; - break; - case SADB_EXT_SUPPORTED_ENCRYPT: - if (alg_id > SADB_EALG_MAX) - return NULL; - break; - default: - return NULL; - } - - switch (satype) - { - case SADB_SATYPE_ESP: - alg_p = (exttype == SADB_EXT_SUPPORTED_ENCRYPT)? - &esp_ealg[alg_id] : &esp_aalg[alg_id]; - /* get for write: increment elem count */ - if (rw) - { - (exttype == SADB_EXT_SUPPORTED_ENCRYPT)? - esp_ealg_num++ : esp_aalg_num++; - } - break; - case SADB_SATYPE_AH: - default: - return NULL; - } - - return alg_p; -} - -const struct sadb_alg* kernel_alg_sadb_alg_get(int satype, int exttype, - int alg_id) -{ - return sadb_alg_ptr(satype, exttype, alg_id, 0); -} - -/* - * Forget previous registration - */ -static void kernel_alg_init(void) -{ - DBG(DBG_KERNEL, - DBG_log("alg_init(): memset(%p, 0, %d) memset(%p, 0, %d)", - &esp_aalg, (int)sizeof (esp_aalg), - &esp_ealg, (int)sizeof (esp_ealg)) - ) - memset (&esp_aalg, 0, sizeof (esp_aalg)); - memset (&esp_ealg, 0, sizeof (esp_ealg)); - esp_ealg_num=esp_aalg_num = 0; -} - -static int kernel_alg_add(int satype, int exttype, - const struct sadb_alg *sadb_alg) -{ - struct sadb_alg *alg_p = NULL; - int alg_id = sadb_alg->sadb_alg_id; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_add(): satype=%d, exttype=%d, alg_id=%d", - satype, exttype, sadb_alg->sadb_alg_id) - ) - if (!(alg_p = sadb_alg_ptr(satype, exttype, alg_id, 1))) - return -1; - - /* This logic "mimics" KLIPS: first algo implementation will be used */ - if (alg_p->sadb_alg_id) - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_add(): discarding already setup " - "satype=%d, exttype=%d, alg_id=%d", - satype, exttype, sadb_alg->sadb_alg_id) - ) - return 0; - } - *alg_p = *sadb_alg; - return 1; -} - -bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, - struct alg_info_esp *alg_info __attribute__((unused))) -{ - struct sadb_alg *alg_p = NULL; - - /* - * test #1: encrypt algo must be present - */ - int ret = ESP_EALG_PRESENT(alg_id); - if (!ret) goto out; - - alg_p = &esp_ealg[alg_id]; - - /* - * test #2: if key_len specified, it must be in range - */ - if (key_len - && (key_len < alg_p->sadb_alg_minbits || key_len > alg_p->sadb_alg_maxbits)) - { - plog("kernel_alg_db_add() key_len not in range: alg_id=%d, " - "key_len=%d, alg_minbits=%d, alg_maxbits=%d" - , alg_id, key_len - , alg_p->sadb_alg_minbits - , alg_p->sadb_alg_maxbits); - ret = FALSE; - } - -out: - if (ret) - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_ok(%d,%d): " - "alg_id=%d, " - "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " - "res=%d, ret=%d" - , alg_id, key_len - , alg_p->sadb_alg_id - , alg_p->sadb_alg_ivlen - , alg_p->sadb_alg_minbits - , alg_p->sadb_alg_maxbits - , alg_p->sadb_alg_reserved - , ret); - ) - } - else - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO", alg_id, key_len); - ) - } - return ret; -} - -/* - * ML: make F_STRICT logic consider enc,auth algorithms - */ -bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, - struct alg_info_esp *alg_info) -{ - int ealg_insecure; - - /* - * key_len passed comes from esp_attrs read from peer - * For many older algorithms (eg 3DES) this key_len is fixed - * and get passed as 0. - * ... then get default key_len - */ - if (key_len == 0) - key_len = kernel_alg_esp_enc_keylen(ealg) * BITS_PER_BYTE; - - /* - * simple test to toss low key_len, will accept it only - * if specified in "esp" string - */ - ealg_insecure = (key_len < 128) ; - - if (ealg_insecure - || (alg_info && alg_info->alg_info_flags & ALG_INFO_F_STRICT)) - { - int i; - struct esp_info *esp_info; - - if (alg_info) - { - ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) - { - if (esp_info->esp_ealg_id == ealg - && (esp_info->esp_ealg_keylen == 0 || key_len == 0 - || esp_info->esp_ealg_keylen == key_len) - && esp_info->esp_aalg_id == aalg) - { - if (ealg_insecure) - { - loglog(RC_LOG_SERIOUS - , "You should NOT use insecure ESP algorithms [%s (%d)]!" - , enum_name(&esp_transform_names, ealg), key_len); - } - return TRUE; - } - } - } - plog("IPSec Transform [%s (%d), %s] refused due to %s", - enum_name(&esp_transform_names, ealg), key_len, - enum_name(&auth_alg_names, aalg), - ealg_insecure ? "insecure key_len and enc. alg. not listed in \"esp\" string" : "strict flag"); - return FALSE; - } - return TRUE; -} - -/** - * Load kernel_alg arrays pluto's SADB_REGISTER user by pluto/kernel.c - */ -void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen) -{ - /* Trick: one 'type-mangle-able' pointer to ease offset/assign */ - union { - const struct sadb_msg *msg; - const struct sadb_supported *supported; - const struct sadb_ext *ext; - const struct sadb_alg *alg; - const char *ch; - } sadb; - - int satype; - int msglen; - int i = 0; - - /* Initialize alg arrays */ - kernel_alg_init(); - satype = msg_buf->sadb_msg_satype; - sadb.msg = msg_buf; - msglen = sadb.msg->sadb_msg_len*IPSEC_PFKEYv2_ALIGN; - msglen -= sizeof(struct sadb_msg); - buflen -= sizeof(struct sadb_msg); - passert(buflen > 0); - - sadb.msg++; - - while (msglen) - { - int supp_exttype = sadb.supported->sadb_supported_exttype; - int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " - "sadb_msg_len=%d sadb_supported_len=%d" - , satype==SADB_SATYPE_ESP? "ESP" : "AH" - , msg_buf->sadb_msg_len, supp_len) - ) - sadb.supported++; - msglen -= supp_len; - buflen -= supp_len; - passert(buflen >= 0); - - for (supp_len -= sizeof(struct sadb_supported); - supp_len; - supp_len -= sizeof(struct sadb_alg), sadb.alg++,i++) - { - kernel_alg_add(satype, supp_exttype, sadb.alg); - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " - "alg[%d], exttype=%d, satype=%d, alg_id=%d, " - "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " - "res=%d" - , satype == SADB_SATYPE_ESP? "ESP" : "AH" - , i - , supp_exttype - , satype - , sadb.alg->sadb_alg_id - , sadb.alg->sadb_alg_ivlen - , sadb.alg->sadb_alg_minbits - , sadb.alg->sadb_alg_maxbits - , sadb.alg->sadb_alg_reserved) - ) - /* if AES_CBC is registered then also register AES_CCM and AES_GCM */ - if (satype == SADB_SATYPE_ESP && - supp_exttype == SADB_EXT_SUPPORTED_ENCRYPT && - sadb.alg->sadb_alg_id == SADB_X_EALG_AESCBC) - { - struct sadb_alg alg = *sadb.alg; - int alg_id; - - for (alg_id = SADB_X_EALG_AES_CCM_ICV8; - alg_id <= SADB_X_EALG_AES_GCM_ICV16; alg_id++) - { - if (alg_id != ESP_UNASSIGNED_17) - { - alg.sadb_alg_id = alg_id; - kernel_alg_add(satype, supp_exttype, &alg); - } - } - - /* also register AES_GMAC */ - alg.sadb_alg_id = SADB_X_EALG_NULL_AES_GMAC; - kernel_alg_add(satype, supp_exttype, &alg); - } - /* if SHA2_256 is registered then also register SHA2_256_96 */ - if (satype == SADB_SATYPE_ESP && - supp_exttype == SADB_EXT_SUPPORTED_AUTH && - sadb.alg->sadb_alg_id == SADB_X_AALG_SHA2_256HMAC) - { - struct sadb_alg alg = *sadb.alg; - - alg.sadb_alg_id = SADB_X_AALG_SHA2_256_96HMAC; - kernel_alg_add(satype, supp_exttype, &alg); - } - } - } -} - -u_int kernel_alg_esp_enc_keylen(u_int alg_id) -{ - u_int keylen = 0; - - if (!ESP_EALG_PRESENT(alg_id)) - { - goto none; - } - keylen = esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE; - - switch (alg_id) - { - /* - * this is veryUgly[TM] - * Peer should have sent KEY_LENGTH attribute for ESP_AES - * but if not do force it to 128 instead of using sadb_alg_maxbits - * from kernel. - */ - case ESP_AES: - keylen = 128/BITS_PER_BYTE; - break; - } - -none: - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_keylen(): alg_id=%d, keylen=%d", - alg_id, keylen) - ) - return keylen; -} - -struct sadb_alg* kernel_alg_esp_sadb_alg(u_int alg_id) -{ - struct sadb_alg *sadb_alg = (ESP_EALG_PRESENT(alg_id)) - ? &esp_ealg[alg_id] : NULL; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p" - , alg_id, sadb_alg) - ) - return sadb_alg; -} - -/** - * Print the name of a kernel algorithm - */ -static void print_alg(char *buf, int *len, enum_names *alg_names, int alg_type) -{ - char alg_name[BUF_LEN]; - int alg_name_len; - - alg_name_len = sprintf(alg_name, " %s", enum_name(alg_names, alg_type)); - if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE) - { - whack_log(RC_COMMENT, "%s", buf); - *len = sprintf(buf, " "); - } - sprintf(buf + *len, "%s", alg_name); - *len += alg_name_len; -} - -void kernel_alg_list(void) -{ - char buf[BUF_LEN]; - int len; - u_int sadb_id; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered ESP Algorithms:"); - whack_log(RC_COMMENT, " "); - - len = sprintf(buf, " encryption:"); - for (sadb_id = 1; sadb_id <= SADB_EALG_MAX; sadb_id++) - { - if (ESP_EALG_PRESENT(sadb_id)) - { - print_alg(buf, &len, &esp_transform_names, sadb_id); - } - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " integrity: "); - for (sadb_id = 1; sadb_id <= SADB_AALG_MAX; sadb_id++) - { - if (ESP_AALG_PRESENT(sadb_id)) - { - u_int aaid = alg_info_esp_sadb2aa(sadb_id); - - print_alg(buf, &len, &auth_alg_names, aaid); - } - } - whack_log(RC_COMMENT, "%s", buf); -} - -void kernel_alg_show_connection(connection_t *c, const char *instance) -{ - struct state *st = state_with_serialno(c->newest_ipsec_sa); - - if (st && st->st_esp.present) - { - const char *aalg_name, *pfsgroup_name; - - aalg_name = (c->policy & POLICY_AUTHENTICATE) ? - enum_show(&ah_transform_names, st->st_ah.attrs.transid): - enum_show(&auth_alg_names, st->st_esp.attrs.auth); - - pfsgroup_name = (c->policy & POLICY_PFS) ? - (c->alg_info_esp && c->alg_info_esp->esp_pfsgroup) ? - enum_show(&oakley_group_names, - c->alg_info_esp->esp_pfsgroup) : - "" : ""; - - if (st->st_esp.attrs.key_len) - { - whack_log(RC_COMMENT, "\"%s\"%s: ESP%s proposal: %s_%u/%s/%s", - c->name, instance, - (st->st_ah.present) ? "/AH" : "", - enum_show(&esp_transform_names, st->st_esp.attrs.transid), - st->st_esp.attrs.key_len, aalg_name, pfsgroup_name); - } - else - { - whack_log(RC_COMMENT, "\"%s\"%s: ESP%s proposal: %s/%s/%s", - c->name, instance, - (st->st_ah.present) ? "/AH" : "", - enum_show(&esp_transform_names, st->st_esp.attrs.transid), - aalg_name, pfsgroup_name); - } - } -} - -bool kernel_alg_esp_auth_ok(u_int auth, - struct alg_info_esp *alg_info __attribute__((unused))) -{ - return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth)); -} - -u_int kernel_alg_esp_auth_keylen(u_int auth) -{ - u_int sadb_aalg = alg_info_esp_aa2sadb(auth); - - u_int a_keylen = (sadb_aalg) - ? esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE - : 0; - - DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING, - DBG_log("kernel_alg_esp_auth_keylen(auth=%d, sadb_aalg=%d): " - "a_keylen=%d", auth, sadb_aalg, a_keylen) - ) - return a_keylen; -} - -struct esp_info* kernel_alg_esp_info(int transid, int auth) -{ - int sadb_aalg, sadb_ealg; - static struct esp_info ei_buf; - - sadb_ealg = transid; - sadb_aalg = alg_info_esp_aa2sadb(auth); - - if (!ESP_EALG_PRESENT(sadb_ealg)) - goto none; - if (!ESP_AALG_PRESENT(sadb_aalg)) - goto none; - - memset(&ei_buf, 0, sizeof (ei_buf)); - ei_buf.transid = transid; - ei_buf.auth = auth; - - /* don't return "default" keylen because this value is used from - * setup_half_ipsec_sa() to "validate" keylen - * In effect, enckeylen will be used as "max" value - */ - ei_buf.enckeylen = esp_ealg[sadb_ealg].sadb_alg_maxbits/BITS_PER_BYTE; - ei_buf.authkeylen = esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE; - ei_buf.encryptalg = sadb_ealg; - ei_buf.authalg = sadb_aalg; - - DBG(DBG_PARSING, - DBG_log("kernel_alg_esp_info():" - "transid=%d, auth=%d, ei=%p, " - "enckeylen=%d, authkeylen=%d, encryptalg=%d, authalg=%d", - transid, auth, &ei_buf, - (int)ei_buf.enckeylen, (int)ei_buf.authkeylen, - ei_buf.encryptalg, ei_buf.authalg) - ) - return &ei_buf; - -none: - DBG(DBG_PARSING, - DBG_log("kernel_alg_esp_info():" - "transid=%d, auth=%d, ei=NULL", - transid, auth) - ) - return NULL; -} - -static void kernel_alg_policy_algorithms(struct esp_info *esp_info) -{ - u_int ealg_id = esp_info->esp_ealg_id; - - switch(ealg_id) - { - case 0: - case ESP_DES: - case ESP_3DES: - case ESP_NULL: - case ESP_CAST: - break; - default: - if (!esp_info->esp_ealg_keylen) - { - /* algos that need KEY_LENGTH - * - * Note: this is a very dirty hack ;-) - * Idea: Add a key_length_needed attribute to - * esp_ealg ?? - */ - esp_info->esp_ealg_keylen = esp_ealg[ealg_id].sadb_alg_maxbits; - } - } -} - -static bool kernel_alg_db_add(struct db_context *db_ctx, - struct esp_info *esp_info, lset_t policy) -{ - u_int ealg_id, aalg_id; - - ealg_id = esp_info->esp_ealg_id; - - if (!ESP_EALG_PRESENT(ealg_id)) - { - DBG_log("kernel_alg_db_add() kernel enc ealg_id=%d not present", ealg_id); - return FALSE; - } - - if (!(policy & POLICY_AUTHENTICATE) && /* skip ESP auth attrs for AH */ - esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE) - { - aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id); - - if (!ESP_AALG_PRESENT(aalg_id)) - { - DBG_log("kernel_alg_db_add() kernel auth aalg_id=%d not present", - aalg_id); - return FALSE; - } - } - - /* do algo policy */ - kernel_alg_policy_algorithms(esp_info); - - /* open new transformation */ - db_trans_add(db_ctx, ealg_id); - - /* add ESP auth attr if not AH or AEAD */ - if (!(policy & POLICY_AUTHENTICATE) && - esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE) - { - db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id); - } - - /* add keylength if specified in esp= string */ - if (esp_info->esp_ealg_keylen) - { - db_attr_add_values(db_ctx, KEY_LENGTH, esp_info->esp_ealg_keylen); - } - - return TRUE; -} - -/* - * Create proposal with runtime kernel algos, merging - * with passed proposal if not NULL - * - * for now this function does free() previous returned - * malloced pointer (this quirk allows easier spdb.c change) - */ -struct db_context* kernel_alg_db_new(struct alg_info_esp *alg_info, - lset_t policy) -{ - const struct esp_info *esp_info; - struct esp_info tmp_esp_info; - struct db_context *ctx_new = NULL; - u_int trans_cnt = esp_ealg_num * esp_aalg_num; - - if (!(policy & POLICY_ENCRYPT)) /* not possible, I think */ - { - return NULL; - } - - /* pass aprox. number of transforms and attributes */ - ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2); - - if (alg_info) - { - int i; - - ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) - { - tmp_esp_info = *esp_info; - kernel_alg_db_add(ctx_new, &tmp_esp_info, policy); - } - } - return ctx_new; -} - diff --git a/src/pluto/kernel_alg.h b/src/pluto/kernel_alg.h deleted file mode 100644 index 4c757db41..000000000 --- a/src/pluto/kernel_alg.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Kernel runtime algorithm handling interface definitions - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _KERNEL_ALG_H -#define _KERNEL_ALG_H - -#include "alg_info.h" -#include "spdb.h" - -/* status info */ -extern void kernel_alg_show_status(void); -void kernel_alg_show_connection(struct connection *c, const char *instance); - -/* Registration messages from pluto */ -extern void kernel_alg_register_pfkey(const struct sadb_msg *msg, int buflen); - -/* ESP interface */ -extern struct sadb_alg *kernel_alg_esp_sadb_alg(u_int alg_id); -extern u_int kernel_alg_esp_ivlen(u_int alg_id); -extern bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, struct alg_info_esp *nfo); -extern bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info); -extern u_int kernel_alg_esp_enc_keylen(u_int alg_id); -extern bool kernel_alg_esp_auth_ok(u_int auth, struct alg_info_esp *nfo); -extern u_int kernel_alg_esp_auth_keylen(u_int auth); -extern void kernel_alg_list(void); - -/* get sadb_alg for passed args */ -extern const struct sadb_alg * kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id); - -extern struct db_context * kernel_alg_db_new(struct alg_info_esp *ai, lset_t policy); -struct esp_info * kernel_alg_esp_info(int esp_id, int auth_id); -#endif /* _KERNEL_ALG_H */ diff --git a/src/pluto/kernel_pfkey.c b/src/pluto/kernel_pfkey.c deleted file mode 100644 index 77fff2f9e..000000000 --- a/src/pluto/kernel_pfkey.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2003 Herbert Xu. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 1997 Angelos D. Keromytis. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "constants.h" -#include "kernel.h" -#include "kernel_pfkey.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "kernel_alg.h" - - -static int pfkeyfd = NULL_FD; - -typedef u_int32_t pfkey_seq_t; -static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */ - -static pid_t pid; - -#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */ - -static sparse_names pfkey_type_names = { - NE(SADB_RESERVED), - NE(SADB_GETSPI), - NE(SADB_UPDATE), - NE(SADB_ADD), - NE(SADB_DELETE), - NE(SADB_GET), - NE(SADB_ACQUIRE), - NE(SADB_REGISTER), - NE(SADB_EXPIRE), - NE(SADB_FLUSH), - NE(SADB_DUMP), - NE(SADB_X_PROMISC), - NE(SADB_X_PCHANGE), - NE(SADB_X_GRPSA), - NE(SADB_X_ADDFLOW), - NE(SADB_X_DELFLOW), - NE(SADB_X_DEBUG), - NE(SADB_X_NAT_T_NEW_MAPPING), - NE(SADB_MAX), - { 0, sparse_end } -}; - -#undef NE - -typedef union { - unsigned char bytes[PFKEYv2_MAX_MSGSIZE]; - struct sadb_msg msg; - } pfkey_buf; - -static bool -pfkey_input_ready(void) -{ - int ndes; - fd_set readfds; - struct timeval tm = { .tv_sec = 0 }; /* don't wait, polling */ - - FD_ZERO(&readfds); /* we only care about pfkeyfd */ - FD_SET(pfkeyfd, &readfds); - - do { - ndes = select(pfkeyfd + 1, &readfds, NULL, NULL, &tm); - } while (ndes == -1 && errno == EINTR); - - if (ndes < 0) - { - log_errno((e, "select() failed in pfkey_get()")); - return FALSE; - } - else if (ndes == 0) - { - return FALSE; /* nothing to read */ - } - passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds)); - return TRUE; -} - -/* get a PF_KEY message from kernel. - * Returns TRUE if message found, FALSE if no message pending, - * and aborts or keeps trying when an error is encountered. - * The only validation of the message is that the message length - * received matches that in the message header, and that the message - * is for this process. - */ -static bool -pfkey_get(pfkey_buf *buf) -{ - for (;;) - { - /* len must be less than PFKEYv2_MAX_MSGSIZE, - * so it should fit in an int. We use this fact when printing it. - */ - ssize_t len; - - if (!pfkey_input_ready()) - { - return FALSE; - } - - len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes)); - - if (len < 0) - { - if (errno == EAGAIN) - { - return FALSE; - } - log_errno((e, "read() failed in pfkey_get()")); - return FALSE; - } - else if ((size_t)len < sizeof(buf->msg)) - { - plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring", - (int)len); - } - else if ((size_t)len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN) - { - plog("pfkey_get read PF_KEY message with length %d that doesn't" - " equal sadb_msg_len %u * %u; ignoring message", (int)len, - (unsigned)buf->msg.sadb_msg_len, (unsigned)IPSEC_PFKEYv2_ALIGN); - } - else if (buf->msg.sadb_msg_pid != (unsigned)pid) - { - /* not for us: ignore */ - DBG(DBG_KERNEL, - DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process" - " %u", sparse_val_show(pfkey_type_names, - buf->msg.sadb_msg_type), - buf->msg.sadb_msg_seq, buf->msg.sadb_msg_pid)); - } - else - { - DBG(DBG_KERNEL, - DBG_log("pfkey_get: %s message %u", - sparse_val_show(pfkey_type_names, - buf->msg.sadb_msg_type), - buf->msg.sadb_msg_seq)); - return TRUE; - } - } -} - -/* get a response to a specific message */ -static bool -pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq) -{ - while (pfkey_get(buf)) - { - if (buf->msg.sadb_msg_seq == seq) - { - return TRUE; - } - } - return FALSE; -} - -static bool -pfkey_build(int error, const char *description, const char *text_said, - struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - if (error != 0) - { - loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d", description, - text_said, error); - pfkey_extensions_free(extensions); - return FALSE; - } - return TRUE; -} - -/* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */ -static bool -pfkey_msg_start(u_int8_t msg_type, u_int8_t satype, const char *description, - const char *text_said, - struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - pfkey_extensions_init(extensions); - return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type, satype, 0, - ++pfkey_seq, pid), - description, text_said, extensions); -} - -/* Finish (building, sending, accepting response for) PF_KEY message. - * If response isn't NULL, the response from the kernel will be - * placed there (and its errno field will not be examined). - * Returns TRUE iff all appears well. - */ -static bool -finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1], - const char *description, const char *text_said, - pfkey_buf *response) -{ - struct sadb_msg *pfkey_msg; - bool success = TRUE; - int error; - - error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN); - - if (error != 0) - { - loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d", - description, text_said, error); - success = FALSE; - } - else - { - size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN; - - DBG(DBG_KERNEL, - DBG_log("finish_pfkey_msg: %s message %u for %s %s", - sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type), - pfkey_msg->sadb_msg_seq, description, text_said); - DBG_dump(NULL, (void *) pfkey_msg, len)); - - ssize_t r = write(pfkeyfd, pfkey_msg, len); - - if (r != (ssize_t)len) - { - if (r < 0) - { - log_errno((e, "pfkey write() of %s message %u for %s %s" - " failed", sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq, - description, text_said)); - } - else - { - loglog(RC_LOG_SERIOUS, "ERROR: pfkey write() of %s message" - " %u for %s %s truncated: %ld instead of %ld", - sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq, - description, text_said, (long)r, (long)len); - } - success = FALSE; - - /* if we were compiled with debugging, but we haven't already - * dumped the command, do so. - */ -#ifdef DEBUG - if ((cur_debugging & DBG_KERNEL) == 0) - DBG_dump(NULL, (void *) pfkey_msg, len); -#endif - } - else - { - /* Check response from kernel. - * It ought to be an echo, perhaps with additional info. - * If the caller wants it, response will point to space. - */ - pfkey_buf b; - pfkey_buf *bp = response != NULL? response : &b; - - if (!pfkey_get_response(bp, - ((struct sadb_msg *)extensions[0])->sadb_msg_seq)) - { - loglog(RC_LOG_SERIOUS, "ERROR: no response to our PF_KEY %s" - " message for %s %s", sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), description, text_said); - success = FALSE; - } - else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type) - { - loglog(RC_LOG_SERIOUS, "ERROR: response to our PF_KEY %s" - " message for %s %s was of wrong type (%s)", - sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type), - description, text_said, sparse_val_show(pfkey_type_names, - bp->msg.sadb_msg_type)); - success = FALSE; - } - else if (response == NULL && bp->msg.sadb_msg_errno != 0) - { - /* Kernel is signalling a problem */ - loglog(RC_LOG_SERIOUS, "ERROR: PF_KEY %s response for %s %s" - " included errno %u: %s", - sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), description, text_said, - (unsigned) bp->msg.sadb_msg_errno, - strerror(bp->msg.sadb_msg_errno)); - success = FALSE; - } - } - } - pfkey_extensions_free(extensions); - pfkey_msg_free(&pfkey_msg); - return success; -} - -/* Process a SADB_REGISTER message from the kernel. - * This will be a response to one of ours, but it may be asynchronous - * (if kernel modules are loaded and unloaded). - * Some sanity checking has already been performed. - */ -static void -pfkey_register_response(const struct sadb_msg *msg) -{ - /* Find out what the kernel can support. - */ - switch (msg->sadb_msg_satype) - { - case SADB_SATYPE_ESP: -#ifndef NO_KERNEL_ALG - kernel_alg_register_pfkey(msg, sizeof (pfkey_buf)); -#endif - break; - case SADB_X_SATYPE_IPCOMP: - /* ??? There ought to be an extension to list the - * supported algorithms, but RFC 2367 doesn't - * list one for IPcomp. - */ - can_do_IPcomp = TRUE; - break; - default: - break; - } -} - -/** register SA types that can be negotiated */ -static void -pfkey_register_proto(unsigned satype, const char *satypename) -{ - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - pfkey_buf pfb; - - if (!(pfkey_msg_start(SADB_REGISTER, satype, satypename, NULL, extensions) - && finish_pfkey_msg(extensions, satypename, "", &pfb))) - { - /* ??? should this be loglog */ - plog("no kernel support for %s", satypename); - } - else - { - pfkey_register_response(&pfb.msg); - DBG(DBG_KERNEL, - DBG_log("%s registered with kernel.", satypename)); - } -} - -void -pfkey_register(void) -{ - pid = getpid(); - - pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); - if (pfkeyfd == -1) - { - exit_log_errno((e, "socket() in init_pfkeyfd()")); - } - - pfkey_register_proto(SADB_SATYPE_AH, "AH"); - pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); - pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP"); - - close(pfkeyfd); -} diff --git a/src/pluto/kernel_pfkey.h b/src/pluto/kernel_pfkey.h deleted file mode 100644 index b50ad6c37..000000000 --- a/src/pluto/kernel_pfkey.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * Register our capabilities via PF_KEY, also learn the kernel's capabilities, - * i.e. the supported algorithms. - */ -void pfkey_register(); diff --git a/src/pluto/keys.c b/src/pluto/keys.c deleted file mode 100644 index 5fcbdfa40..000000000 --- a/src/pluto/keys.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* mechanisms for preshared keys (public, private, and preshared secrets) - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* missing from on old systems */ -#include - -#ifdef HAVE_GLOB_H -#include -#ifndef GLOB_ABORTED -# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */ -#endif -#endif - -#include - -#include -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "x509.h" -#include "certs.h" -#include "smartcard.h" -#include "connections.h" -#include "state.h" -#include "lex.h" -#include "keys.h" -#include "adns.h" /* needs */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "timer.h" -#include "fetch.h" - -const char *shared_secrets_file = SHARED_SECRETS_FILE; - - -typedef enum secret_kind_t secret_kind_t; - -enum secret_kind_t { - SECRET_PSK, - SECRET_PUBKEY, - SECRET_XAUTH, - SECRET_PIN -}; - -typedef struct secret_t secret_t; - -struct secret_t { - linked_list_t *ids; - secret_kind_t kind; - union { - chunk_t preshared_secret; - private_key_t *private_key; - smartcard_t *smartcard; - } u; - secret_t *next; -}; - -/* - * free a public key struct - */ -static void free_public_key(pubkey_t *pk) -{ - DESTROY_IF(pk->id); - DESTROY_IF(pk->public_key); - DESTROY_IF(pk->issuer); - free(pk->serial.ptr); - free(pk); -} - -secret_t *secrets = NULL; - -/** - * Find the secret associated with the combination of me and the peer. - */ -const secret_t* match_secret(identification_t *my_id, identification_t *his_id, - secret_kind_t kind) -{ - enum { /* bits */ - match_default = 0x01, - match_him = 0x02, - match_me = 0x04 - }; - - unsigned int best_match = 0; - secret_t *s, *best = NULL; - - for (s = secrets; s != NULL; s = s->next) - { - unsigned int match = 0; - - if (s->kind != kind) - { - continue; - } - - if (s->ids->get_count(s->ids) == 0) - { - /* a default (signified by lack of ids): - * accept if no more specific match found - */ - match = match_default; - } - else - { - /* check if both ends match ids */ - enumerator_t *enumerator; - identification_t *id; - - enumerator = s->ids->create_enumerator(s->ids); - while (enumerator->enumerate(enumerator, &id)) - { - if (my_id->equals(my_id, id)) - { - match |= match_me; - } - if (his_id->equals(his_id, id)) - { - match |= match_him; - } - } - enumerator->destroy(enumerator); - - /* If our end matched the only id in the list, - * default to matching any peer. - * A more specific match will trump this. - */ - if (match == match_me && s->ids->get_count(s->ids) == 1) - { - match |= match_default; - } - } - - switch (match) - { - case match_me: - /* if this is an asymmetric (eg. public key) system, - * allow this-side-only match to count, even if - * there are other ids in the list. - */ - if (kind != SECRET_PUBKEY) - { - break; - } - /* FALLTHROUGH */ - case match_default: /* default all */ - case match_me | match_default: /* default peer */ - case match_me | match_him: /* explicit */ - if (match == best_match) - { - /* two good matches are equally good: do they agree? */ - bool same = FALSE; - - switch (kind) - { - case SECRET_PSK: - case SECRET_XAUTH: - same = chunk_equals(s->u.preshared_secret, - best->u.preshared_secret); - break; - case SECRET_PUBKEY: - same = s->u.private_key->equals(s->u.private_key, - best->u.private_key); - break; - default: - bad_case(kind); - } - if (!same) - { - loglog(RC_LOG_SERIOUS, "multiple ipsec.secrets entries with " - "distinct secrets match endpoints: first secret used"); - best = s; /* list is backwards: take latest in list */ - } - } - else if (match > best_match) - { - /* this is the best match so far */ - best_match = match; - best = s; - } - } - } - return best; -} - -/** - * Retrieves an XAUTH secret primarily based on the user ID and - * secondarily based on the server ID - */ -bool get_xauth_secret(identification_t *user, identification_t *server, - chunk_t *secret) -{ - const secret_t *s; - - s = match_secret(user, server, SECRET_XAUTH); - if (s) - { - *secret = chunk_clone(s->u.preshared_secret); - return TRUE; - } - else - { - *secret = chunk_empty; - return FALSE; - } -} - -/** - * We match the ID (if none, the IP address). Failure is indicated by a NULL. - */ -static const secret_t* get_secret(const connection_t *c, secret_kind_t kind) -{ - identification_t *my_id, *his_id; - const secret_t *best; - - my_id = c->spd.this.id; - - if (his_id_was_instantiated(c)) - { - /* roadwarrior: replace him with 0.0.0.0 */ - his_id = identification_create_from_string("%any"); - } - else if (kind == SECRET_PSK && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) && - ((c->kind == CK_TEMPLATE && - c->spd.that.id->get_type(c->spd.that.id) == ID_ANY) || - (c->kind == CK_INSTANCE && id_is_ipaddr(c->spd.that.id)))) - { - /* roadwarrior: replace him with 0.0.0.0 */ - his_id = identification_create_from_string("%any"); - } - else - { - his_id = c->spd.that.id->clone(c->spd.that.id); - } - - best = match_secret(my_id, his_id, kind); - - his_id->destroy(his_id); - return best; -} - -/* find the appropriate preshared key (see get_secret). - * Failure is indicated by a NULL pointer. - * Note: the result is not to be freed by the caller. - */ -const chunk_t* get_preshared_secret(const connection_t *c) -{ - const secret_t *s = get_secret(c, SECRET_PSK); - - DBG(DBG_PRIVATE, - if (s == NULL) - DBG_log("no Preshared Key Found"); - else - DBG_dump_chunk("Preshared Key", s->u.preshared_secret); - ) - return s == NULL? NULL : &s->u.preshared_secret; -} - -/* check the existence of a private key matching a public key contained - * in an X.509 or OpenPGP certificate - */ -bool has_private_key(cert_t *cert) -{ - secret_t *s; - bool has_key = FALSE; - public_key_t *pub_key = cert->cert->get_public_key(cert->cert); - - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, pub_key)) - { - has_key = TRUE; - break; - } - } - pub_key->destroy(pub_key); - return has_key; -} - -/* - * get the matching private key belonging to a given X.509 certificate - */ -private_key_t* get_x509_private_key(const cert_t *cert) -{ - public_key_t *public_key = cert->cert->get_public_key(cert->cert); - private_key_t *private_key = NULL; - secret_t *s; - - for (s = secrets; s != NULL; s = s->next) - { - - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, public_key)) - { - private_key = s->u.private_key; - break; - } - } - public_key->destroy(public_key); - return private_key; -} - -/* find the appropriate private key (see get_secret). - * Failure is indicated by a NULL pointer. - */ -private_key_t* get_private_key(const connection_t *c) -{ - const secret_t *s, *best = NULL; - - /* is a certificate assigned to this connection? */ - if (c->spd.this.cert) - { - certificate_t *certificate; - public_key_t *pub_key; - - certificate = c->spd.this.cert->cert; - pub_key = certificate->get_public_key(certificate); - - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, pub_key)) - { - best = s; - break; /* found the private key - no sense in searching further */ - } - } - pub_key->destroy(pub_key); - } - else - { - best = get_secret(c, SECRET_PUBKEY); - } - return best ? best->u.private_key : NULL; -} - -/* digest a secrets file - * - * The file is a sequence of records. A record is a maximal sequence of - * tokens such that the first, and only the first, is in the first column - * of a line. - * - * Tokens are generally separated by whitespace and are key words, ids, - * strings, or data suitable for ttodata(3). As a nod to convention, - * a trailing ":" on what would otherwise be a token is taken as a - * separate token. If preceded by whitespace, a "#" is taken as starting - * a comment: it and the rest of the line are ignored. - * - * One kind of record is an include directive. It starts with "include". - * The filename is the only other token in the record. - * If the filename does not start with /, it is taken to - * be relative to the directory containing the current file. - * - * The other kind of record describes a key. It starts with a - * sequence of ids and ends with key information. Each id - * is an IP address, a Fully Qualified Domain Name (which will immediately - * be resolved), or @FQDN which will be left as a name. - * - * The key part can be in several forms. - * - * The old form of the key is still supported: a simple - * quoted strings (with no escapes) is taken as a preshred key. - * - * The new form starts the key part with a ":". - * - * For Preshared Key, use the "PSK" keyword, and follow it by a string - * or a data token suitable for ttodata(3). - * - * For RSA Private Key, use the "RSA" keyword, followed by a - * brace-enclosed list of key field keywords and data values. - * The data values are large integers to be decoded by ttodata(3). - * The fields are a subset of those used by BIND 8.2 and have the - * same names. - */ - -/* parse PSK from file */ -static err_t process_psk_secret(chunk_t *psk) -{ - err_t ugh = NULL; - - if (*tok == '"' || *tok == '\'') - { - chunk_t secret = { tok + 1, flp->cur - tok -2 }; - - *psk = chunk_clone(secret); - (void) shift(); - } - else - { - char buf[BUF_LEN]; /* limit on size of binary representation of key */ - size_t sz; - - ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz - , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh != NULL) - { - /* ttodata didn't like PSK data */ - ugh = builddiag("PSK data malformed (%s): %s", ugh, tok); - } - else - { - chunk_t secret = { buf, sz }; - *psk = chunk_clone(secret); - (void) shift(); - } - } - return ugh; -} - -typedef enum rsa_private_key_part_t rsa_private_key_part_t; - -enum rsa_private_key_part_t { - RSA_PART_MODULUS = 0, - RSA_PART_PUBLIC_EXPONENT = 1, - RSA_PART_PRIVATE_EXPONENT = 2, - RSA_PART_PRIME1 = 3, - RSA_PART_PRIME2 = 4, - RSA_PART_EXPONENT1 = 5, - RSA_PART_EXPONENT2 = 6, - RSA_PART_COEFFICIENT = 7 -}; - -const char *rsa_private_key_part_names[] = { - "Modulus", - "PublicExponent", - "PrivateExponent", - "Prime1", - "Prime2", - "Exponent1", - "Exponent2", - "Coefficient" -}; - -/** - * Parse fields of an RSA private key in BIND 8.2's representation - * consistiong of a braced list of keyword and value pairs in required order. - */ -static err_t process_rsa_secret(private_key_t **key) -{ - chunk_t rsa_chunk[countof(rsa_private_key_part_names)]; - u_char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */ - rsa_private_key_part_t part, p; - size_t sz; - err_t ugh; - - for (part = RSA_PART_MODULUS; part <= RSA_PART_COEFFICIENT; part++) - { - const char *keyword = rsa_private_key_part_names[part]; - - if (!shift()) - { - ugh = "premature end of RSA key"; - goto end; - } - if (!tokeqword(keyword)) - { - ugh = builddiag("%s keyword not found where expected in RSA key" - , keyword); - goto end; - } - if (!(shift() && (!tokeq(":") || shift()))) /* ignore optional ":" */ - { - ugh = "premature end of RSA key"; - goto end; - } - ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz, - diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh) - { - ugh = builddiag("RSA data malformed (%s): %s", ugh, tok); - goto end; - } - rsa_chunk[part] = chunk_create(buf, sz); - rsa_chunk[part] = chunk_clone(rsa_chunk[part]); - } - - /* We require an (indented) '}' and the end of the record. - * We break down the test so that the diagnostic will be more helpful. - * Some people don't seem to wish to indent the brace! - */ - if (!shift() || !tokeq("}")) - { - ugh = "malformed end of RSA private key -- indented '}' required"; - goto end; - } - if (shift()) - { - ugh = "malformed end of RSA private key -- unexpected token after '}'"; - goto end; - } - - *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_RSA_MODULUS, rsa_chunk[RSA_PART_MODULUS], - BUILD_RSA_PUB_EXP, rsa_chunk[RSA_PART_PUBLIC_EXPONENT], - BUILD_RSA_PRIV_EXP, rsa_chunk[RSA_PART_PRIVATE_EXPONENT], - BUILD_RSA_PRIME1, rsa_chunk[RSA_PART_PRIME1], - BUILD_RSA_PRIME2, rsa_chunk[RSA_PART_PRIME2], - BUILD_RSA_EXP1, rsa_chunk[RSA_PART_EXPONENT1], - BUILD_RSA_EXP2, rsa_chunk[RSA_PART_EXPONENT2], - BUILD_RSA_COEFF, rsa_chunk[RSA_PART_COEFFICIENT], - BUILD_END); - - if (*key == NULL) - { - ugh = "parsing of RSA private key failed"; - } - -end: - /* clean up and return */ - for (p = RSA_PART_MODULUS ; p < part; p++) - { - chunk_clear(&rsa_chunk[p]); - } - return ugh; -} - -/* struct used to prompt for a secret passphrase - * from a console with file descriptor fd - */ -typedef struct { - char secret[PROMPT_PASS_LEN+1]; - bool prompt; - int fd; - int try; -} prompt_pass_t; - -/** - * Passphrase callback to read from whack fd - */ -static shared_key_t* whack_pass_cb(prompt_pass_t *pass, shared_key_type_t type, - identification_t *me, identification_t *other, - id_match_t *match_me, id_match_t *match_other) -{ - int n; - - if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS) - { - return NULL; - } - - if (pass->try > MAX_PROMPT_PASS_TRIALS) - { - whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials"); - return NULL; - } - if (pass->try == 1) - { - whack_log(RC_ENTERSECRET, "need passphrase for 'private key'"); - } - else - { - whack_log(RC_ENTERSECRET, "invalid passphrase, please try again"); - } - pass->try++; - - n = read(pass->fd, pass->secret, PROMPT_PASS_LEN); - if (n == -1) - { - whack_log(RC_LOG_SERIOUS, "read(whackfd) failed"); - return NULL; - } - pass->secret[n-1] = '\0'; - - if (strlen(pass->secret) == 0) - { - whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted"); - return NULL; - } - if (match_me) - { - *match_me = ID_MATCH_PERFECT; - } - if (match_other) - { - *match_other = ID_MATCH_NONE; - } - return shared_key_create(SHARED_PRIVATE_KEY_PASS, - chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); -} - -/** - * Loads a PKCS#1 or PGP private key file - */ -static private_key_t* load_private_key(char* filename, prompt_pass_t *pass, - key_type_t type) -{ - private_key_t *key = NULL; - char *path; - - path = concatenate_paths(PRIVATE_KEY_PATH, filename); - if (pass && pass->prompt && pass->fd != NULL_FD) - { /* use passphrase callback */ - callback_cred_t *cb; - - cb = callback_cred_create_shared((void*)whack_pass_cb, pass); - lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE); - - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - lib->credmgr->remove_local_set(lib->credmgr, &cb->set); - cb->destroy(cb); - if (key) - { - whack_log(RC_SUCCESS, "valid passphrase"); - } - } - else if (pass) - { /* use a given passphrase */ - mem_cred_t *mem; - shared_key_t *shared; - - mem = mem_cred_create(); - lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE); - shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, - chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); - mem->add_shared(mem, shared, NULL); - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - lib->credmgr->remove_local_set(lib->credmgr, &mem->set); - mem->destroy(mem); - } - else - { /* no passphrase */ - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - - } - if (key) - { - plog(" loaded private key from '%s'", filename); - } - else - { - plog(" syntax error in private key file"); - } - return key; -} - -/** - * process a key file protected with optional passphrase which can either be - * read from ipsec.secrets or prompted for by using whack - */ -static err_t process_keyfile(private_key_t **key, key_type_t type, int whackfd) -{ - char filename[BUF_LEN]; - prompt_pass_t pass; - - memset(filename,'\0', BUF_LEN); - memset(pass.secret,'\0', sizeof(pass.secret)); - pass.prompt = FALSE; - pass.fd = whackfd; - pass.try = 1; - - /* we expect the filename of a PKCS#1 private key file */ - - if (*tok == '"' || *tok == '\'') /* quoted filename */ - memcpy(filename, tok+1, flp->cur - tok - 2); - else - memcpy(filename, tok, flp->cur - tok); - - if (shift()) - { - /* we expect an appended passphrase or passphrase prompt*/ - if (tokeqword("%prompt")) - { - if (pass.fd == NULL_FD) - { - return "Private key file -- enter passphrase using 'ipsec secrets'"; - } - pass.prompt = TRUE; - } - else - { - char *passphrase = tok; - size_t len = flp->cur - passphrase; - - if (*tok == '"' || *tok == '\'') /* quoted passphrase */ - { - passphrase++; - len -= 2; - } - if (len > PROMPT_PASS_LEN) - { - return "Private key file -- passphrase exceeds 64 characters"; - } - memcpy(pass.secret, passphrase, len); - } - if (shift()) - { - return "Private key file -- unexpected token after passphrase"; - } - } - *key = load_private_key(filename, &pass, type); - - return *key ? NULL : "Private key file -- could not be loaded"; -} - -/** - * Process pin read from ipsec.secrets or prompted for it using whack - */ -static err_t process_pin(secret_t *s, int whackfd) -{ - smartcard_t *sc; - const char *pin_status = "no pin"; - - s->kind = SECRET_PIN; - - /* looking for the smartcard keyword */ - if (!shift() || strncmp(tok, SCX_TOKEN, strlen(SCX_TOKEN)) != 0) - return "PIN keyword must be followed by %smartcard:"; - - sc = scx_add(scx_parse_number_slot_id(tok + strlen(SCX_TOKEN))); - s->u.smartcard = sc; - scx_share(sc); - if (sc->pin.ptr != NULL) - { - scx_release_context(sc); - scx_free_pin(&sc->pin); - } - sc->valid = FALSE; - - if (!shift()) - return "PIN statement must be terminated either by , %pinpad or %prompt"; - - if (tokeqword("%prompt")) - { - shift(); - /* if whackfd exists, whack will be used to prompt for a pin */ - if (whackfd != NULL_FD) - pin_status = scx_get_pin(sc, whackfd) ? "valid pin" : "invalid pin"; - else - pin_status = "pin entry via prompt"; - } - else if (tokeqword("%pinpad")) - { - chunk_t empty_pin = { "", 0 }; - - shift(); - - /* pin will be entered via pin pad during verification */ - sc->pin = chunk_clone(empty_pin); - sc->pinpad = TRUE; - sc->valid = TRUE; - pin_status = "pin entry via pad"; - if (pkcs11_keep_state) - { - scx_verify_pin(sc); - } - } - else - { - /* we read the pin directly from ipsec.secrets */ - err_t ugh = process_psk_secret(&sc->pin); - if (ugh != NULL) - return ugh; - /* verify the pin */ - pin_status = scx_verify_pin(sc) ? "valid PIN" : "invalid PIN"; - } -#ifdef SMARTCARD - { - char buf[BUF_LEN]; - - if (sc->any_slot) - snprintf(buf, BUF_LEN, "any slot"); - else - snprintf(buf, BUF_LEN, "slot: %lu", sc->slot); - - plog(" %s for #%d (%s, id: %s)" - , pin_status, sc->number, scx_print_slot(sc, ""), sc->id); - } -#else - plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); -#endif - return NULL; -} - -static void log_psk(char *label, secret_t *s) -{ - int n = 0; - char buf[BUF_LEN]; - enumerator_t *enumerator; - identification_t *id; - - if (s->ids->get_count(s->ids) == 0) - { - n = snprintf(buf, BUF_LEN, "%%any"); - } - else - { - enumerator = s->ids->create_enumerator(s->ids); - while(enumerator->enumerate(enumerator, &id)) - { - n += snprintf(buf + n, BUF_LEN - n, "%Y ", id); - if (n >= BUF_LEN) - { - n = BUF_LEN - 1; - break; - } - } - enumerator->destroy(enumerator); - } - plog(" loaded %s secret for %.*s", label, n, buf); -} - -static void process_secret(secret_t *s, int whackfd) -{ - err_t ugh = NULL; - - s->kind = SECRET_PSK; /* default */ - if (tokeqword("psk")) - { - log_psk("PSK", s); - - /* preshared key: quoted string or ttodata format */ - ugh = !shift()? "unexpected end of record in PSK" - : process_psk_secret(&s->u.preshared_secret); - } - else if (tokeqword("xauth")) - { - s->kind = SECRET_XAUTH; - log_psk("XAUTH", s); - - /* xauth secret: quoted string or ttodata format */ - ugh = !shift()? "unexpected end of record in XAUTH" - : process_psk_secret(&s->u.preshared_secret); - } - else if (tokeqword("rsa")) - { - /* RSA key: the fun begins. - * A braced list of keyword and value pairs. - */ - s->kind = SECRET_PUBKEY; - if (!shift()) - { - ugh = "bad RSA key syntax"; - } - else if (tokeq("{")) - { - ugh = process_rsa_secret(&s->u.private_key); - } - else - { - ugh = process_keyfile(&s->u.private_key, KEY_RSA, whackfd); - } - } - else if (tokeqword("ecdsa")) - { - s->kind = SECRET_PUBKEY; - if (!shift()) - { - ugh = "bad ECDSA key syntax"; - } - else - { - ugh = process_keyfile(&s->u.private_key, KEY_ECDSA, whackfd); - } - } - else if (tokeqword("pin")) - { - ugh = process_pin(s, whackfd); - } - else - { - ugh = builddiag("unrecognized key format: %s", tok); - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s" - , flp->filename, flp->lino, ugh); - s->ids->destroy_offset(s->ids, offsetof(identification_t, destroy)); - free(s); - } - else if (flushline("expected record boundary in key")) - { - /* gauntlet has been run: install new secret */ - lock_certs_and_keys("process_secret"); - s->next = secrets; - secrets = s; - unlock_certs_and_keys("process_secrets"); - } -} - -static void process_secrets_file(const char *file_pat, int whackfd); /* forward declaration */ - -static void process_secret_records(int whackfd) -{ - /* read records from ipsec.secrets and load them into our table */ - for (;;) - { - (void)flushline(NULL); /* silently ditch leftovers, if any */ - if (flp->bdry == B_file) - { - break; - } - flp->bdry = B_none; /* eat the Record Boundary */ - (void)shift(); /* get real first token */ - - if (tokeqword("include")) - { - /* an include directive */ - char fn[MAX_TOK_LEN]; /* space for filename (I hope) */ - char *p = fn; - char *end_prefix = strrchr(flp->filename, '/'); - - if (!shift()) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of include directive" - , flp->filename, flp->lino); - continue; /* abandon this record */ - } - - /* if path is relative and including file's pathname has - * a non-empty dirname, prefix this path with that dirname. - */ - if (tok[0] != '/' && end_prefix != NULL) - { - size_t pl = end_prefix - flp->filename + 1; - - /* "clamp" length to prevent problems now; - * will be rediscovered and reported later. - */ - if (pl > sizeof(fn)) - { - pl = sizeof(fn); - } - memcpy(fn, flp->filename, pl); - p += pl; - } - if (flp->cur - tok >= &fn[sizeof(fn)] - p) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: include pathname too long" - , flp->filename, flp->lino); - continue; /* abandon this record */ - } - strcpy(p, tok); - (void) shift(); /* move to Record Boundary, we hope */ - if (flushline("ignoring malformed INCLUDE -- expected Record Boundary after filename")) - { - process_secrets_file(fn, whackfd); - tok = NULL; /* correct, but probably redundant */ - } - } - else - { - /* expecting a list of indices and then the key info */ - secret_t *s = malloc_thing(secret_t); - - zero(s); - s->ids = linked_list_create(); - s->kind = SECRET_PSK; /* default */ - s->u.preshared_secret = chunk_empty; - s->next = NULL; - - for (;;) - { - if (tokeq(":")) - { - /* found key part */ - shift(); /* discard explicit separator */ - process_secret(s, whackfd); - break; - } - else - { - identification_t *id; - - id = identification_create_from_string(tok); - s->ids->insert_last(s->ids, id); - - if (!shift()) - { - /* unexpected Record Boundary or EOF */ - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end" - " of id list", flp->filename, flp->lino); - s->ids->destroy_offset(s->ids, - offsetof(identification_t, destroy)); - free(s); - break; - } - } - } - } - } -} - -static int globugh(const char *epath, int eerrno) -{ - log_errno_routine(eerrno, "problem with secrets file \"%s\"", epath); - return 1; /* stop glob */ -} - -static void process_secrets_file(const char *file_pat, int whackfd) -{ - struct file_lex_position pos; - char **fnp; - - pos.depth = flp == NULL? 0 : flp->depth + 1; - - if (pos.depth > 10) - { - loglog(RC_LOG_SERIOUS, "preshared secrets file \"%s\" nested too deeply", file_pat); - return; - } - -#ifdef HAVE_GLOB_H - /* do globbing */ - { - glob_t globbuf; - int r = glob(file_pat, GLOB_ERR, globugh, &globbuf); - - if (r != 0) - { - switch (r) - { - case GLOB_NOSPACE: - loglog(RC_LOG_SERIOUS, "out of space processing secrets filename \"%s\"", file_pat); - break; - case GLOB_ABORTED: - break; /* already logged */ - case GLOB_NOMATCH: - loglog(RC_LOG_SERIOUS, "no secrets filename matched \"%s\"", file_pat); - break; - default: - loglog(RC_LOG_SERIOUS, "unknown glob error %d", r); - break; - } - globfree(&globbuf); - return; - } - - /* for each file... */ - for (fnp = globbuf.gl_pathv; *fnp != NULL; fnp++) - { - if (lexopen(&pos, *fnp, FALSE)) - { - plog("loading secrets from \"%s\"", *fnp); - flushline("file starts with indentation (continuation notation)"); - process_secret_records(whackfd); - lexclose(); - } - } - - globfree(&globbuf); - } -#else /* HAVE_GLOB_H */ - /* if glob(3) is not available, try to load pattern directly */ - if (lexopen(&pos, file_pat, FALSE)) - { - plog("loading secrets from \"%s\"", file_pat); - flushline("file starts with indentation (continuation notation)"); - process_secret_records(whackfd); - lexclose(); - } -#endif /* HAVE_GLOB_H */ -} - -void free_preshared_secrets(void) -{ - lock_certs_and_keys("free_preshared_secrets"); - - if (secrets != NULL) - { - secret_t *s, *ns; - - plog("forgetting secrets"); - - for (s = secrets; s != NULL; s = ns) - { - ns = s->next; - s->ids->destroy_offset(s->ids, offsetof(identification_t, destroy)); - - switch (s->kind) - { - case SECRET_PSK: - case SECRET_XAUTH: - free(s->u.preshared_secret.ptr); - break; - case SECRET_PUBKEY: - DESTROY_IF(s->u.private_key); - break; - case SECRET_PIN: - scx_release(s->u.smartcard); - break; - default: - bad_case(s->kind); - } - free(s); - } - secrets = NULL; - } - - unlock_certs_and_keys("free_preshard_secrets"); -} - -void load_preshared_secrets(int whackfd) -{ - free_preshared_secrets(); - (void) process_secrets_file(shared_secrets_file, whackfd); -} - -/* public key machinery - * Note: caller must set dns_auth_level. - */ - -pubkey_t* public_key_from_rsa(public_key_t *key) -{ - pubkey_t *p = malloc_thing(pubkey_t); - - zero(p); - p->id = identification_create_from_string("%any"); /* don't know, doesn't matter */ - p->issuer = NULL; - p->serial = chunk_empty; - p->public_key = key; - - /* note that we return a 1 reference count upon creation: - * invariant: recount > 0. - */ - p->refcnt = 1; - return p; -} - -/* Free a public key record. - * As a convenience, this returns a pointer to next. - */ -pubkey_list_t* free_public_keyentry(pubkey_list_t *p) -{ - pubkey_list_t *nxt = p->next; - - if (p->key != NULL) - { - unreference_key(&p->key); - } - free(p); - return nxt; -} - -void free_public_keys(pubkey_list_t **keys) -{ - while (*keys != NULL) - { - *keys = free_public_keyentry(*keys); - } -} - -/* root of chained public key list */ - -pubkey_list_t *pubkeys = NULL; /* keys from ipsec.conf */ - -void free_remembered_public_keys(void) -{ - free_public_keys(&pubkeys); -} - -/** - * Transfer public keys from *keys list to front of pubkeys list - */ -void transfer_to_public_keys(struct gw_info *gateways_from_dns -#ifdef USE_KEYRR -, pubkey_list_t **keys -#endif /* USE_KEYRR */ -) -{ - { - struct gw_info *gwp; - - for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - pubkey_list_t *pl = malloc_thing(pubkey_list_t); - - pl->key = gwp->key; /* note: this is a transfer */ - gwp->key = NULL; /* really, it is! */ - pl->next = pubkeys; - pubkeys = pl; - } - } - -#ifdef USE_KEYRR - { - pubkey_list_t **pp = keys; - - while (*pp != NULL) - { - pp = &(*pp)->next; - } - *pp = pubkeys; - pubkeys = *keys; - *keys = NULL; - } -#endif /* USE_KEYRR */ -} - - -static void install_public_key(pubkey_t *pk, pubkey_list_t **head) -{ - pubkey_list_t *p = malloc_thing(pubkey_list_t); - - /* install new key at front */ - p->key = reference_key(pk); - p->next = *head; - *head = p; -} - -void delete_public_keys(identification_t *id, key_type_t type, - identification_t *issuer, chunk_t serial) -{ - pubkey_list_t **pp, *p; - pubkey_t *pk; - key_type_t pk_type; - - for (pp = &pubkeys; (p = *pp) != NULL; ) - { - pk = p->key; - pk_type = pk->public_key->get_type(pk->public_key); - - if (id->equals(id, pk->id) && pk_type == type - && (issuer == NULL || pk->issuer == NULL - || issuer->equals(issuer, pk->issuer)) - && (serial.ptr == NULL || chunk_equals(serial, pk->serial))) - { - *pp = free_public_keyentry(p); - } - else - { - pp = &p->next; - } - } -} - -pubkey_t* reference_key(pubkey_t *pk) -{ - DBG(DBG_CONTROLMORE, - DBG_log(" ref key: %p %p cnt %d '%Y'", - pk, pk->public_key, pk->refcnt, pk->id) - ) - pk->refcnt++; - return pk; -} - -void unreference_key(pubkey_t **pkp) -{ - pubkey_t *pk = *pkp; - - if (pk == NULL) - { - return; - } - - DBG(DBG_CONTROLMORE, - DBG_log("unref key: %p %p cnt %d '%Y'", - pk, pk->public_key, pk->refcnt, pk->id) - ) - - /* cancel out the pointer */ - *pkp = NULL; - - passert(pk->refcnt != 0); - pk->refcnt--; - if (pk->refcnt == 0) - { - free_public_key(pk); - } -} - -bool add_public_key(identification_t *id, enum dns_auth_level dns_auth_level, - enum pubkey_alg alg, chunk_t rfc3110_key, - pubkey_list_t **head) -{ - public_key_t *key = NULL; - pubkey_t *pk; - - /* first: algorithm-specific decoding of key chunk */ - switch (alg) - { - case PUBKEY_ALG_RSA: - key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, - BUILD_BLOB_DNSKEY, rfc3110_key, - BUILD_END); - if (key == NULL) - { - return FALSE; - } - break; - default: - bad_case(alg); - } - - pk = malloc_thing(pubkey_t); - zero(pk); - pk->public_key = key; - pk->id = id->clone(id); - pk->dns_auth_level = dns_auth_level; - pk->until_time = UNDEFINED_TIME; - pk->issuer = NULL; - pk->serial = chunk_empty; - install_public_key(pk, head); - return TRUE; -} - -/** - * Extract id and public key a certificate and insert it into a pubkeyrec - */ -void add_public_key_from_cert(cert_t *cert , time_t until, - enum dns_auth_level dns_auth_level) -{ - certificate_t *certificate = cert->cert; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = NULL; - identification_t *id; - chunk_t serialNumber = chunk_empty; - pubkey_t *pk; - key_type_t pk_type; - - /* ID type: ID_DER_ASN1_DN (X.509 subject field) */ - pk = malloc_thing(pubkey_t); - zero(pk); - pk->public_key = certificate->get_public_key(certificate); - pk_type = pk->public_key->get_type(pk->public_key); - pk->id = subject->clone(subject); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - if (certificate->get_type(certificate) == CERT_X509) - { - x509_t *x509 = (x509_t*)certificate; - - issuer = certificate->get_issuer(certificate); - serialNumber = x509->get_serial(x509); - pk->issuer = issuer->clone(issuer); - pk->serial = chunk_clone(serialNumber); - } - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - - if (certificate->get_type(certificate) == CERT_X509) - { - x509_t *x509 = (x509_t*)certificate; - enumerator_t *enumerator; - - /* insert all subjectAltNames from X.509 certificates */ - enumerator = x509->create_subjectAltName_enumerator(x509); - while (enumerator->enumerate(enumerator, &id)) - { - if (id->get_type(id) != ID_ANY) - { - pk = malloc_thing(pubkey_t); - zero(pk); - pk->id = id->clone(id); - pk->public_key = certificate->get_public_key(certificate); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - pk->issuer = issuer->clone(issuer); - pk->serial = chunk_clone(serialNumber); - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - } - } - enumerator->destroy(enumerator); - } - else - { - pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; - chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); - - /* add v3 or v4 PGP fingerprint */ - pk = malloc_thing(pubkey_t); - zero(pk); - pk->id = identification_create_from_encoding(ID_KEY_ID, fingerprint); - pk->public_key = certificate->get_public_key(certificate); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - } -} - -/* when a X.509 certificate gets revoked, all instances of - * the corresponding public key must be removed - */ -void remove_x509_public_key(const cert_t *cert) -{ - public_key_t *revoked_key = cert->cert->get_public_key(cert->cert); - pubkey_list_t *p, **pp; - - p = pubkeys; - pp = &pubkeys; - - while(p != NULL) - { - if (revoked_key->equals(revoked_key, p->key->public_key)) - { - /* remove p from list and free memory */ - *pp = free_public_keyentry(p); - loglog(RC_LOG_SERIOUS, "invalid public key deleted"); - } - else - { - pp = &p->next; - } - p =*pp; - } - revoked_key->destroy(revoked_key); -} - -/* - * list all public keys in the chained list - */ -void list_public_keys(bool utc) -{ - pubkey_list_t *p = pubkeys; - chunk_t serial; - - if (p != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Public Keys:"); - } - - while (p != NULL) - { - pubkey_t *key = p->key; - public_key_t *public = key->public_key; - chunk_t keyid; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " identity: '%Y'", key->id); - whack_log(RC_COMMENT, " pubkey: %N %4d bits, until %T %s", - key_type_names, public->get_type(public), - public->get_keysize(public), - &key->until_time, utc, - check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE)); - if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - whack_log(RC_COMMENT," keyid: %#B", &keyid); - } - if (key->issuer) - { - whack_log(RC_COMMENT," issuer: \"%Y\"", key->issuer); - } - if (key->serial.len) - { - serial = chunk_skip_zero(key->serial); - whack_log(RC_COMMENT," serial: %#B", &serial); - } - p = p->next; - } -} diff --git a/src/pluto/keys.h b/src/pluto/keys.h deleted file mode 100644 index 73cc21392..000000000 --- a/src/pluto/keys.h +++ /dev/null @@ -1,93 +0,0 @@ -/* mechanisms for preshared keys (public, private, and preshared secrets) - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen, Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _KEYS_H -#define _KEYS_H - -#include -#include -#include - -#include "certs.h" -#include "connections.h" - -#ifndef SHARED_SECRETS_FILE -# define SHARED_SECRETS_FILE IPSEC_CONFDIR "/ipsec.secrets" -#endif - -const char *shared_secrets_file; - -extern void load_preshared_secrets(int whackfd); -extern void free_preshared_secrets(void); - -extern void xauth_defaults(void); - -extern bool get_xauth_secret(identification_t *user, identification_t *server, - chunk_t *secret); -extern const chunk_t *get_preshared_secret(const connection_t *c); -extern private_key_t *get_private_key(const connection_t *c); -extern private_key_t *get_x509_private_key(const cert_t *cert); - -/* public key machinery */ - -typedef struct pubkey pubkey_t; - -struct pubkey { - identification_t *id; - unsigned refcnt; /* reference counted! */ - enum dns_auth_level dns_auth_level; - char *dns_sig; - time_t last_tried_time, last_worked_time, until_time; - identification_t *issuer; - chunk_t serial; - public_key_t *public_key; -}; - -typedef struct pubkey_list pubkey_list_t; - -struct pubkey_list { - pubkey_t *key; - pubkey_list_t *next; -}; - -extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */ - -extern pubkey_t *public_key_from_rsa(public_key_t *key); -extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p); -extern void free_public_keys(pubkey_list_t **keys); -extern void free_remembered_public_keys(void); -extern void delete_public_keys(identification_t *id, key_type_t type, - identification_t *issuer, chunk_t serial); -extern pubkey_t *reference_key(pubkey_t *pk); -extern void unreference_key(pubkey_t **pkp); -extern bool add_public_key(identification_t *id, - enum dns_auth_level dns_auth_level, - enum pubkey_alg alg, - chunk_t rfc3110_key, - pubkey_list_t **head); -extern bool has_private_key(cert_t *cert); -extern void add_public_key_from_cert(cert_t *cert, time_t until, - enum dns_auth_level dns_auth_level); -extern void remove_x509_public_key(const cert_t *cert); -extern void list_public_keys(bool utc); - -struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ -extern void transfer_to_public_keys(struct gw_info *gateways_from_dns -#ifdef USE_KEYRR - , pubkey_list_t **keys -#endif /* USE_KEYRR */ - ); - -#endif /* _KEYS_H */ diff --git a/src/pluto/lex.c b/src/pluto/lex.c deleted file mode 100644 index d5ebdaba9..000000000 --- a/src/pluto/lex.c +++ /dev/null @@ -1,211 +0,0 @@ -/* lexer (lexical analyzer) for control files - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "lex.h" - -struct file_lex_position *flp = NULL; - -/* Open a file for lexical processing. - * new_flp and name must point into storage with will live - * at least until the file is closed. - */ -bool -lexopen(struct file_lex_position *new_flp, const char *name, bool optional) -{ - FILE *f = fopen(name, "r"); - - if (f == NULL) - { - if (!optional || errno != ENOENT) - log_errno((e, "could not open \"%s\"", name)); - return FALSE; - } - else - { - new_flp->previous = flp; - flp = new_flp; - flp->filename = name; - flp->fp = f; - flp->lino = 0; - flp->bdry = B_none; - - flp->cur = flp->buffer; /* nothing loaded yet */ - flp->under = *flp->cur = '\0'; - - (void) shift(); /* prime tok */ - return TRUE; - } -} - -void -lexclose(void) -{ - fclose(flp->fp); - flp = flp->previous; -} - -/* Token decoding: shift() loads the next token into tok. - * Iff a token starts at the left margin, it is considered - * to be the first in a record. We create a special condition, - * Record Boundary (analogous to EOF), just before such a token. - * We are unwilling to shift through a record boundary: - * it must be overridden first. - * Returns FALSE iff Record Boundary or EOF (i.e. no token); - * tok will then be NULL. - */ - -char *tok; -#define tokeq(s) (streq(tok, (s))) -#define tokeqword(s) (strcasecmp(tok, (s)) == 0) - -bool -shift(void) -{ - char *p = flp->cur; - char *sor = NULL; /* start of record for any new lines */ - - passert(flp->bdry == B_none); - - *p = flp->under; - flp->under = '\0'; - - for (;;) - { - switch (*p) - { - case '\0': /* end of line */ - case '#': /* comment to end of line: treat as end of line */ - /* get the next line */ - if (fgets(flp->buffer, sizeof(flp->buffer)-1, flp->fp) == NULL) - { - flp->bdry = B_file; - tok = flp->cur = NULL; - return FALSE; - } - else - { - /* strip trailing whitespace, including \n */ - - for (p = flp->buffer+strlen(flp->buffer)-1 - ; p>flp->buffer && isspace(p[-1]); p--) - ; - *p = '\0'; - - flp->lino++; - sor = p = flp->buffer; - } - break; /* try again for a token */ - - case ' ': /* whitespace */ - case '\t': - p++; - break; /* try again for a token */ - - case '"': /* quoted token */ - case '\'': - if (p != sor) - { - /* we have a quoted token: note and advance to its end */ - tok = p; - p = strchr(p+1, *p); - if (p == NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unterminated string" - , flp->filename, flp->lino); - p = tok + strlen(tok); - } - else - { - p++; /* include delimiter in token */ - } - - /* remember token delimiter and replace with '\0' */ - flp->under = *p; - *p = '\0'; - flp->cur = p; - return TRUE; - } - /* FALL THROUGH */ - default: - if (p != sor) - { - /* we seem to have a token: note and advance to its end */ - tok = p; - - if (p[0] == '0' && p[1] == 't') - { - /* 0t... token goes to end of line */ - p += strlen(p); - } - else - { - /* "ordinary" token: up to whitespace or end of line */ - do { - p++; - } while (*p != '\0' && !isspace(*p)) - ; - - /* fudge to separate ':' from a preceding adjacent token */ - if (p-1 > tok && p[-1] == ':') - p--; - } - - /* remember token delimiter and replace with '\0' */ - flp->under = *p; - *p = '\0'; - flp->cur = p; - return TRUE; - } - - /* we have a start-of-record: return it, deferring "real" token */ - flp->bdry = B_record; - tok = NULL; - flp->under = *p; - flp->cur = p; - return FALSE; - } - } -} - -/* ensures we are at a Record (or File) boundary, optionally warning if not */ - -bool -flushline(const char *m) -{ - if (flp->bdry != B_none) - { - return TRUE; - } - else - { - if (m != NULL) - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s", flp->filename, flp->lino, m); - do {} while (shift()); - return FALSE; - } -} diff --git a/src/pluto/lex.h b/src/pluto/lex.h deleted file mode 100644 index aa0be7829..000000000 --- a/src/pluto/lex.h +++ /dev/null @@ -1,50 +0,0 @@ -/* lexer (lexical analyzer) for control files - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#define MAX_TOK_LEN 2048 /* includes terminal '\0' */ -struct file_lex_position -{ - int depth; /* how deeply we are nested */ - const char *filename; - FILE *fp; - enum { B_none, B_record, B_file } bdry; /* current boundary */ - int lino; /* line number in file */ - char buffer[MAX_TOK_LEN + 1]; /* note: one extra char for our use (jamming '"') */ - char *cur; /* cursor */ - char under; /* except in shift(): character originally at *cur */ - struct file_lex_position *previous; -}; - -extern struct file_lex_position *flp; - -extern bool lexopen(struct file_lex_position *new_flp, const char *name, bool optional); -extern void lexclose(void); - - -/* Token decoding: shift() loads the next token into tok. - * Iff a token starts at the left margin, it is considered - * to be the first in a record. We create a special condition, - * Record Boundary (analogous to EOF), just before such a token. - * We are unwilling to shift through a record boundary: - * it must be overridden first. - * Returns FALSE iff Record Boundary or EOF (i.e. no token); - * tok will then be NULL. - */ - -extern char *tok; -#define tokeq(s) (streq(tok, (s))) -#define tokeqword(s) (strcasecmp(tok, (s)) == 0) - -extern bool shift(void); -extern bool flushline(const char *m); diff --git a/src/pluto/log.c b/src/pluto/log.c deleted file mode 100644 index f6fa226d5..000000000 --- a/src/pluto/log.c +++ /dev/null @@ -1,946 +0,0 @@ -/* error logging functions - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* used only if MSG_NOSIGNAL not defined */ -#include -#include -#include -#include - -#ifdef ANDROID -#include -#endif - -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "server.h" -#include "state.h" -#include "connections.h" -#include "myid.h" -#include "kernel.h" -#include "whack.h" -#include "whack_attribute.h" -#include "timer.h" - -/* close one per-peer log */ -static void perpeer_logclose(connection_t *c); /* forward */ - - -bool - log_to_stderr = TRUE, /* should log go to stderr? */ - log_to_syslog = TRUE, /* should log go to syslog? */ - log_to_perpeer= FALSE; /* should log go to per-IP file? */ - -bool - logged_txt_warning = FALSE; /* should we complain about finding KEY? */ - -/* should we complain when we find no local id */ -bool - logged_myid_fqdn_txt_warning = FALSE, - logged_myid_ip_txt_warning = FALSE, - logged_myid_fqdn_key_warning = FALSE, - logged_myid_ip_key_warning = FALSE; - -/* may include trailing / */ -const char *base_perpeer_logdir = PERPEERLOGDIR; -static int perpeer_count = 0; - -/* from sys/queue.h */ -static TAILQ_HEAD(perpeer, connection) perpeer_list; - - -/* Context for logging. - * - * Global variables: must be carefully adjusted at transaction boundaries! - * If the context provides a whack file descriptor, messages - * should be copied to it -- see whack_log() - */ -int whack_log_fd = NULL_FD; /* only set during whack_handle() */ -struct state *cur_state = NULL; /* current state, for diagnostics */ -connection_t *cur_connection = NULL; /* current connection, for diagnostics */ -const ip_address *cur_from = NULL; /* source of current current message */ -u_int16_t cur_from_port; /* host order */ - -/** - * pluto dbg function for libstrongswan - */ -static void pluto_dbg(debug_t group, level_t level, char *fmt, ...) -{ - int priority = LOG_INFO; - int debug_level; - char buffer[8192]; - char *current = buffer, *next; - va_list args; - - if (cur_debugging & DBG_PRIVATE) - { - debug_level = 4; - } - else if (cur_debugging & DBG_RAW) - { - debug_level = 3; - } - else if (cur_debugging & DBG_PARSING) - { - debug_level = 2; - } - else - { - debug_level = 1; - } - - if (level <= debug_level) - { - va_start(args, fmt); - - if (log_to_stderr) - { - if (level > 1) - { - fprintf(stderr, "| "); - } - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - } - if (log_to_syslog -#ifdef ANDROID - || TRUE -#endif - ) - { - /* write in memory buffer first */ - vsnprintf(buffer, sizeof(buffer), fmt, args); - - /* do a syslog with every line */ - while (current) - { - next = strchr(current, '\n'); - if (next) - { - *(next++) = '\0'; - } - syslog(priority, "%s%s\n", (level > 1)? "| ":"", current); -#ifdef ANDROID - __android_log_print(level > 1 ? ANDROID_LOG_DEBUG - : ANDROID_LOG_INFO, "pluto", - "%s%s\n", level > 1 ? "| " : "", current); -#endif - current = next; - } - } - va_end(args); - } -} - -void -init_log(const char *program) -{ - /* enable pluto debugging hook for libstrongswan */ - dbg = pluto_dbg; - - if (log_to_stderr) - { - setbuf(stderr, NULL); - } - if (log_to_syslog) - { - openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV); - } - TAILQ_INIT(&perpeer_list); -} - -void -close_peerlog(void) -{ - /* exit if the queue has not been initialized */ - if (perpeer_list.tqh_first == NULL) - return; - - /* end of queue is given by pointer to "HEAD" */ - while (TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list) - perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer)); -} - -void -close_log(void) -{ - if (log_to_syslog) - closelog(); - - close_peerlog(); -} - -/* Sanitize character string in situ: turns dangerous characters into \OOO. - * With a bit of work, we could use simpler reps for \\, \r, etc., - * but this is only to protect against something that shouldn't be used. - * Truncate resulting string to what fits in buffer. - */ -static size_t -sanitize(char *buf, size_t size) -{ -# define UGLY_WIDTH 4 /* width for ugly character: \OOO */ - size_t len; - size_t added = 0; - char *p; - - passert(size >= UGLY_WIDTH); /* need room to swing cat */ - - /* find right side of string to be sanitized and count - * number of columns to be added. Stop on end of string - * or lack of room for more result. - */ - for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; ) - { - unsigned char c = *p++; - - if (c == '\\' || !isprint(c)) - added += UGLY_WIDTH - 1; - } - - /* at this point, p points after last original character to be - * included. added is how many characters are added to sanitize. - * so p[added] will point after last sanitized character. - */ - - p[added] = '\0'; - len = &p[added] - buf; - - /* scan backwards, copying characters to their new home - * and inserting the expansions for ugly characters. - * It is finished when no more shifting is required. - * This is a predecrement loop. - */ - while (added != 0) - { - char fmtd[UGLY_WIDTH + 1]; - unsigned char c; - - while ((c = *--p) != '\\' && isprint(c)) - p[added] = c; - added -= UGLY_WIDTH - 1; - snprintf(fmtd, sizeof(fmtd), "\\%03o", c); - memcpy(p + added, fmtd, UGLY_WIDTH); - } - return len; -# undef UGLY_WIDTH -} - -/* format a string for the log, with suitable prefixes. - * A format starting with ~ indicates that this is a reprocessing - * of the message, so prefixing and quoting is suppressed. - */ -static void -fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap) -{ - bool reproc = *fmt == '~'; - size_t ps; - connection_t *c = cur_state != NULL ? cur_state->st_connection - : cur_connection; - - buf[0] = '\0'; - if (reproc) - fmt++; /* ~ at start of format suppresses this prefix */ - else if (c != NULL) - { - /* start with name of connection */ - char *const be = buf + buf_len; - char *bp = buf; - - snprintf(bp, be - bp, "\"%s\"", c->name); - bp += strlen(bp); - - /* if it fits, put in any connection instance information */ - if (be - bp > CONN_INST_BUF) - { - fmt_conn_instance(c, bp); - bp += strlen(bp); - } - - if (cur_state != NULL) - { - /* state number */ - snprintf(bp, be - bp, " #%lu", cur_state->st_serialno); - bp += strlen(bp); - } - snprintf(bp, be - bp, ": "); - } - else if (cur_from != NULL) - { - /* peer's IP address */ - /* Note: must not use ip_str() because our caller might! */ - char ab[ADDRTOT_BUF]; - - (void) addrtot(cur_from, 0, ab, sizeof(ab)); - snprintf(buf, buf_len, "packet from %s:%u: " - , ab, (unsigned)cur_from_port); - } - - ps = strlen(buf); - vsnprintf(buf + ps, buf_len - ps, fmt, ap); - if (!reproc) - (void)sanitize(buf, buf_len); -} - -static void -perpeer_logclose(connection_t *c) -{ - /* only free/close things if we had used them! */ - if (c->log_file != NULL) - { - passert(perpeer_count > 0); - - TAILQ_REMOVE(&perpeer_list, c, log_link); - perpeer_count--; - fclose(c->log_file); - c->log_file=NULL; - } -} - -void -perpeer_logfree(connection_t *c) -{ - perpeer_logclose(c); - if (c->log_file_name != NULL) - { - free(c->log_file_name); - c->log_file_name = NULL; - c->log_file_err = FALSE; - } -} - -/* open the per-peer log */ -static void -open_peerlog(connection_t *c) -{ - syslog(LOG_INFO, "opening log file for conn %s", c->name); - - if (c->log_file_name == NULL) - { - char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF]; - int peernamelen, lf_len; - - addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername)); - peernamelen = strlen(peername); - - /* copy IP address, turning : and . into / */ - { - char ch, *p, *q; - - p = peername; - q = dname; - do { - ch = *p++; - if (ch == '.' || ch == ':') - ch = '/'; - *q++ = ch; - } while (ch != '\0'); - } - - lf_len = peernamelen * 2 - + strlen(base_perpeer_logdir) - + sizeof("//.log") - + 1; - c->log_file_name = malloc(lf_len); - - fprintf(stderr, "base dir |%s| dname |%s| peername |%s|" - , base_perpeer_logdir, dname, peername); - snprintf(c->log_file_name, lf_len, "%s/%s/%s.log" - , base_perpeer_logdir, dname, peername); - - syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name); - } - - /* now open the file, creating directories if necessary */ - - { /* create the directory */ - char *dname; - int bpl_len = strlen(base_perpeer_logdir); - char *slashloc; - - dname = clone_str(c->log_file_name); - dname = dirname(dname); - - if (access(dname, W_OK) != 0) - { - if (errno != ENOENT) - { - if (c->log_file_err) - { - syslog(LOG_CRIT, "can not write to %s: %s" - , dname, strerror(errno)); - c->log_file_err = TRUE; - free(dname); - return; - } - } - - /* directory does not exist, walk path creating dirs */ - /* start at base_perpeer_logdir */ - slashloc = dname + bpl_len; - slashloc++; /* since, by construction there is a slash - right there */ - - while (*slashloc != '\0') - { - char saveslash; - - /* look for next slash */ - while (*slashloc != '\0' && *slashloc != '/') slashloc++; - - saveslash = *slashloc; - - *slashloc = '\0'; - - if (mkdir(dname, 0750) != 0 && errno != EEXIST) - { - syslog(LOG_CRIT, "can not create dir %s: %s" - , dname, strerror(errno)); - c->log_file_err = TRUE; - free(dname); - return; - } - syslog(LOG_DEBUG, "created new directory %s", dname); - *slashloc = saveslash; - slashloc++; - } - } - free(dname); - } - - c->log_file = fopen(c->log_file_name, "a"); - if (c->log_file == NULL) - { - if (c->log_file_err) - { - syslog(LOG_CRIT, "logging system can not open %s: %s" - , c->log_file_name, strerror(errno)); - c->log_file_err = TRUE; - } - return; - } - - /* look for a connection to close! */ - while (perpeer_count >= MAX_PEERLOG_COUNT) - { - /* can not be NULL because perpeer_count > 0 */ - passert(TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list); - - perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer)); - } - - /* insert this into the list */ - TAILQ_INSERT_HEAD(&perpeer_list, c, log_link); - passert(c->log_file != NULL); - perpeer_count++; -} - -/* log a line to cur_connection's log */ -static void -peerlog(const char *prefix, const char *m) -{ - if (cur_connection == NULL) - { - /* we can not log it in this case. Oh well. */ - return; - } - - if (cur_connection->log_file == NULL) - { - open_peerlog(cur_connection); - } - - /* despite our attempts above, we may not be able to open the file. */ - if (cur_connection->log_file != NULL) - { - char datebuf[32]; - time_t n; - struct tm *t; - - time(&n); - t = localtime(&n); - - strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t); - fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m); - - /* now move it to the front of the list */ - TAILQ_REMOVE(&perpeer_list, cur_connection, log_link); - TAILQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link); - } -} - -void -plog(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "%s\n", m); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m); -#endif - - whack_log(RC_LOG, "~%s", m); -} - -void -loglog(int mess_no, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "%s\n", m); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m); -#endif - - whack_log(mess_no, "~%s", m); -} - -void -log_errno_routine(int e, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e)); - if (log_to_syslog) - syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e)); - if (log_to_perpeer) - peerlog(strerror(e), m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "ERROR: %s. Errno %d: %s\n", - m, e, strerror(e)); -#endif - - whack_log(RC_LOG_SERIOUS - , "~ERROR: %s. Errno %d: %s", m, e, strerror(e)); -} - -void -exit_log(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "FATAL ERROR: %s\n", m); - if (log_to_syslog) - syslog(LOG_ERR, "FATAL ERROR: %s", m); - if (log_to_perpeer) - peerlog("FATAL ERROR: ", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "FATAL ERROR: %s\n", m); -#endif - - whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m); - - exit_pluto(1); -} - -void -exit_log_errno_routine(int e, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e)); - if (log_to_syslog) - syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e)); - if (log_to_perpeer) - peerlog(strerror(e), m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "FATAL ERROR: %s. " - "Errno %d: %s\n", m, e, strerror(e)); -#endif - - whack_log(RC_LOG_SERIOUS - , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e)); - - exit_pluto(1); -} - -/* emit message to whack. - * form is "ddd statename text" where - * - ddd is a decimal status code (RC_*) as described in whack.h - * - text is a human-readable annotation - */ -#ifdef DEBUG -static volatile sig_atomic_t dying_breath = FALSE; -#endif - -void -whack_log(int mess_no, const char *message, ...) -{ - int wfd = whack_log_fd != NULL_FD ? whack_log_fd - : cur_state != NULL ? cur_state->st_whack_sock - : NULL_FD; - - if (wfd != NULL_FD -#ifdef DEBUG - || dying_breath -#endif - ) - { - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - int prelen = snprintf(m, sizeof(m), "%03d ", mess_no); - - passert(prelen >= 0); - - va_start(args, message); - fmt_log(m+prelen, sizeof(m)-prelen, message, args); - va_end(args); - -#if DEBUG - if (dying_breath) - { - /* status output copied to log */ - if (log_to_stderr) - fprintf(stderr, "%s\n", m + prelen); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m + prelen); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m + prelen); -#endif - } -#endif - - if (wfd != NULL_FD) - { - /* write to whack socket, but suppress possible SIGPIPE */ - size_t len = strlen(m); -#ifdef MSG_NOSIGNAL /* depends on version of glibc??? */ - m[len] = '\n'; /* don't need NUL, do need NL */ - (void) send(wfd, m, len + 1, MSG_NOSIGNAL); -#else /* !MSG_NOSIGNAL */ - int r; - struct sigaction act - , oldact; - - m[len] = '\n'; /* don't need NUL, do need NL */ - act.sa_handler = SIG_IGN; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; /* no nothing */ - r = sigaction(SIGPIPE, &act, &oldact); - passert(r == 0); - - (void) write(wfd, m, len + 1); - - r = sigaction(SIGPIPE, &oldact, NULL); - passert(r == 0); -#endif /* !MSG_NOSIGNAL */ - } - } -} - -/* Build up a diagnostic in a static buffer. - * Although this would be a generally useful function, it is very - * hard to come up with a discipline that prevents different uses - * from interfering. It is intended that by limiting it to building - * diagnostics, we will avoid this problem. - * Juggling is performed to allow an argument to be a previous - * result: the new string may safely depend on the old one. This - * restriction is not checked in any way: violators will produce - * confusing results (without crashing!). - */ -char diag_space[sizeof(diag_space)]; - -err_t -builddiag(const char *fmt, ...) -{ - static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */ - char t[sizeof(diag_space)]; /* build result here first */ - va_list args; - - va_start(args, fmt); - t[0] = '\0'; /* in case nothing terminates string */ - vsnprintf(t, sizeof(t), fmt, args); - va_end(args); - strcpy(diag_space, t); - return diag_space; -} - -/* Debugging message support */ - -#ifdef DEBUG - -void -switch_fail(int n, const char *file_str, unsigned long line_no) -{ - char buf[30]; - - snprintf(buf, sizeof(buf), "case %d unexpected", n); - passert_fail(buf, file_str, line_no); -} - -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no) -{ - /* we will get a possibly unplanned prefix. Hope it works */ - loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str); - if (!dying_breath) - { - dying_breath = TRUE; - show_status(TRUE, NULL); - } - abort(); /* exiting correctly doesn't always work */ -} - -void -pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no) -{ - /* we will get a possibly unplanned prefix. Hope it works */ - loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str); -} - -lset_t - base_debugging = DBG_NONE, /* default to reporting nothing */ - cur_debugging = DBG_NONE; - -void -extra_debugging(const connection_t *c) -{ - if(c == NULL) - { - reset_debugging(); - return; - } - - if (c!= NULL && c->extra_debugging != 0) - { - plog("enabling for connection: %s" - , bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging)); - cur_debugging |= c->extra_debugging; - } -} - -/* log a debugging message (prefixed by "| ") */ - -void -DBG_log(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - vsnprintf(m, sizeof(m), message, args); - va_end(args); - - (void)sanitize(m, sizeof(m)); - - if (log_to_stderr) - fprintf(stderr, "| %s\n", m); - if (log_to_syslog) - syslog(LOG_DEBUG, "| %s", m); - if (log_to_perpeer) - peerlog("| ", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_DEBUG, "pluto", "| %s\n", m); -#endif -} - -/* dump raw bytes in hex to stderr (for lack of any better destination) */ - -void -DBG_dump(const char *label, const void *p, size_t len) -{ -# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */ -# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1) - char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH]; - char *bp; - const unsigned char *cp = p; - - bp = buf; - - if (label != NULL && label[0] != '\0') - { - /* Handle the label. Care must be taken to avoid buffer overrun. */ - size_t llen = strlen(label); - - if (llen + 1 > sizeof(buf)) - { - DBG_log("%s", label); - } - else - { - strcpy(buf, label); - if (buf[llen-1] == '\n') - { - buf[llen-1] = '\0'; /* get rid of newline */ - DBG_log("%s", buf); - } - else if (llen < DUMP_LABEL_WIDTH) - { - bp = buf + llen; - } - else - { - DBG_log("%s", buf); - } - } - } - - do { - int i, j; - - for (i = 0; len!=0 && i!=4; i++) - { - *bp++ = ' '; - for (j = 0; len!=0 && j!=4; len--, j++) - { - static const char hexdig[] = "0123456789abcdef"; - - *bp++ = ' '; - *bp++ = hexdig[(*cp >> 4) & 0xF]; - *bp++ = hexdig[*cp & 0xF]; - cp++; - } - } - *bp = '\0'; - DBG_log("%s", buf); - bp = buf; - } while (len != 0); -# undef DUMP_LABEL_WIDTH -# undef DUMP_WIDTH -} - -#endif /* DEBUG */ - -static void show_loaded_plugins() -{ - whack_log(RC_COMMENT, "loaded plugins: %s", - lib->plugins->loaded_plugins(lib->plugins)); -} - -void show_status(bool all, const char *name) -{ - if (all) - { - whack_log(RC_COMMENT, "Status of IKEv1 pluto daemon (strongSwan "VERSION"):"); - show_ifaces_status(); - show_myid_status(); - show_loaded_plugins(); - show_debug_status(); - show_pools(name); - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - } - show_connections_status(all, name); - show_states_status(all, name); -} - -/* ip_str: a simple to use variant of addrtot. - * It stores its result in a static buffer. - * This means that newer calls overwrite the storage of older calls. - * Note: this is not used in any of the logging functions, so their - * callers may use it. - */ -const char * -ip_str(const ip_address *src) -{ - static char buf[ADDRTOT_BUF]; - - addrtot(src, 0, buf, sizeof(buf)); - return buf; -} - -/* - * a routine that attempts to schedule itself daily. - * - */ - -void -daily_log_reset(void) -{ - /* now perform actions */ - logged_txt_warning = FALSE; - - logged_myid_fqdn_txt_warning = FALSE; - logged_myid_ip_txt_warning = FALSE; - logged_myid_fqdn_key_warning = FALSE; - logged_myid_ip_key_warning = FALSE; -} - -void -daily_log_event(void) -{ - struct tm lt; - time_t t, interval; - - /* attempt to schedule oneself to midnight, local time - * do this by getting seconds in the day, and delaying - * by 86400 - 3600*hours - 60*minutes - seconds. - */ - time(&t); - localtime_r(&t, <); - interval = 3600 * (24 - lt.tm_hour) - 60 * lt.tm_min - lt.tm_sec; - - event_schedule(EVENT_LOG_DAILY, interval, NULL); - daily_log_reset(); -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/log.h b/src/pluto/log.h deleted file mode 100644 index 52c01bbd4..000000000 --- a/src/pluto/log.h +++ /dev/null @@ -1,234 +0,0 @@ -/* logging definitions - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#define LOG_WIDTH 1024 /* roof of number of chars in log line */ - -#ifndef PERPEERLOGDIR -#define PERPEERLOGDIR "/var/log/pluto/peer" -#endif - -/* our versions of assert: log result */ - -#ifdef DEBUG - -extern void passert_fail(const char *pred_str - , const char *file_str, unsigned long line_no) NEVER_RETURNS; - -extern void pexpect_log(const char *pred_str - , const char *file_str, unsigned long line_no); - -# define impossible() passert_fail("impossible", __FILE__, __LINE__) - -extern void switch_fail(int n - , const char *file_str, unsigned long line_no) NEVER_RETURNS; - -# define bad_case(n) switch_fail((int) n, __FILE__, __LINE__) - -# define passert(pred) { \ - if (!(pred)) \ - passert_fail(#pred, __FILE__, __LINE__); \ - } - -# define pexpect(pred) { \ - if (!(pred)) \ - pexpect_log(#pred, __FILE__, __LINE__); \ - } - -/* assert that an err_t is NULL; evaluate exactly once */ -# define happy(x) { \ - err_t ugh = x; \ - if (ugh != NULL) \ - passert_fail(ugh, __FILE__, __LINE__); \ - } - -#else /*!DEBUG*/ - -# define impossible() abort() -# define bad_case(n) abort() -# define passert(pred) { } /* do nothing */ -# define happy(x) { (void) x; } /* evaluate non-judgementally */ - -#endif /*!DEBUG*/ - - -extern bool - log_to_stderr, /* should log go to stderr? */ - log_to_syslog, /* should log go to syslog? */ - log_to_perpeer; /* should log go to per-IP file? */ - -extern const char *base_perpeer_logdir; - -/* maximum number of files to keep open for per-peer log files */ -#define MAX_PEERLOG_COUNT 16 - -/* Context for logging. - * - * Global variables: must be carefully adjusted at transaction boundaries! - * All are to be left in RESET condition and will be checked. - * There are several pairs of routines to set and reset them. - * If the context provides a whack file descriptor, messages - * should be copied to it -- see whack_log() - */ -extern int whack_log_fd; /* only set during whack_handle() */ -extern struct state *cur_state; /* current state, for diagnostics */ -extern struct connection *cur_connection; /* current connection, for diagnostics */ -extern const ip_address *cur_from; /* source of current current message */ -extern u_int16_t cur_from_port; /* host order */ - -#ifdef DEBUG - - extern lset_t cur_debugging; /* current debugging level */ - - extern void extra_debugging(const struct connection *c); - -# define reset_debugging() { cur_debugging = base_debugging; } - -# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \ - && cur_state == NULL \ - && cur_connection == NULL \ - && cur_from == NULL \ - && cur_debugging == base_debugging) - -#else /*!DEBUG*/ - -# define extra_debugging(c) { } - -# define reset_debugging() { } - -# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \ - && cur_state == NULL \ - && cur_connection == NULL \ - && cur_from == NULL) - -#endif /*!DEBUG*/ - -#define reset_globals() { \ - whack_log_fd = NULL_FD; \ - cur_state = NULL; \ - cur_from = NULL; \ - reset_cur_connection(); \ - } - - -#define set_cur_connection(c) { \ - cur_connection = (c); \ - extra_debugging(c); \ - } - -#define reset_cur_connection() { \ - cur_connection = NULL; \ - reset_debugging(); \ - } - - -#define set_cur_state(s) { \ - cur_state = (s); \ - extra_debugging((s)->st_connection); \ - } - -#define reset_cur_state() { \ - cur_state = NULL; \ - reset_debugging(); \ - } - -extern void init_log(const char *program); -extern void close_log(void); -extern void plog(const char *message, ...) PRINTF_LIKE(1); -extern void exit_log(const char *message, ...) PRINTF_LIKE(1) NEVER_RETURNS; - -/* close of all per-peer logging */ -extern void close_peerlog(void); - -/* free all per-peer log resources */ -extern void perpeer_logfree(struct connection *c); - - - -/* the following routines do a dance to capture errno before it is changed - * A call must doubly parenthesize the argument list (no varargs macros). - * The first argument must be "e", the local variable that captures errno. - */ -#define log_errno(a) { int e = errno; log_errno_routine a; } -extern void log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2); -#define exit_log_errno(a) { int e = errno; exit_log_errno_routine a; } -extern void exit_log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2) NEVER_RETURNS NEVER_RETURNS; - -extern void whack_log(int mess_no, const char *message, ...) PRINTF_LIKE(2); - -/* Log to both main log and whack log - * Much like log, actually, except for specifying mess_no. - */ -extern void loglog(int mess_no, const char *message, ...) PRINTF_LIKE(2); - -/* show status, usually on whack log */ -extern void show_status(bool all, const char *name); - -/* Build up a diagnostic in a static buffer. - * Although this would be a generally useful function, it is very - * hard to come up with a discipline that prevents different uses - * from interfering. It is intended that by limiting it to building - * diagnostics, we will avoid this problem. - * Juggling is performed to allow an argument to be a previous - * result: the new string may safely depend on the old one. This - * restriction is not checked in any way: violators will produce - * confusing results (without crashing!). - */ -extern char diag_space[LOG_WIDTH]; /* output buffer, but can be occupied at call */ -extern err_t builddiag(const char *fmt, ...) PRINTF_LIKE(1); - -#ifdef DEBUG - -extern lset_t base_debugging; /* bits selecting what to report */ - -#define DBGP(cond) (cur_debugging & (cond)) -#define DBG(cond, action) { if (DBGP(cond)) { action ; } } - -extern void DBG_log(const char *message, ...) PRINTF_LIKE(1); -extern void DBG_dump(const char *label, const void *p, size_t len); -#define DBG_dump_chunk(label, ch) DBG_dump(label, (ch).ptr, (ch).len) - -#else /*!DEBUG*/ - -#define DBG(cond, action) { } /* do nothing */ - -#endif /*!DEBUG*/ - -#define DBG_cond_dump(cond, label, p, len) DBG(cond, DBG_dump(label, p, len)) -#define DBG_cond_dump_chunk(cond, label, ch) DBG(cond, DBG_dump_chunk(label, ch)) - - -/* ip_str: a simple to use variant of addrtot. - * It stores its result in a static buffer. - * This means that newer calls overwrite the storage of older calls. - * Note: this is not used in any of the logging functions, so their - * callers may use it. - */ -extern const char *ip_str(const ip_address *src); - -/* - * call this routine to reset daily items. - */ -extern void daily_log_reset(void); -extern void daily_log_event(void); - -/* - * some events are to be logged only occasionally. - */ -extern bool logged_txt_warning; -extern bool logged_myid_ip_txt_warning; -extern bool logged_myid_ip_key_warning; -extern bool logged_myid_fqdn_txt_warning; -extern bool logged_myid_fqdn_key_warning; diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c deleted file mode 100644 index 8298ea601..000000000 --- a/src/pluto/modecfg.c +++ /dev/null @@ -1,1263 +0,0 @@ -/* Mode config related functions - * Copyright (C) 2001-2002 Colubris Networks - * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc. - * Copyright (C) 2003-2004 Xelerance Corporation - * Copyright (C) 2006-2010 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * This code originally written by Colubris Networks, Inc. - * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation - * Porting to 2.x by Sean Mathews - */ - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "state.h" -#include "demux.h" -#include "timer.h" -#include "ipsec_doi.h" -#include "log.h" -#include "crypto.h" -#include "modecfg.h" -#include "whack.h" -#include "pluto.h" - -#define MAX_XAUTH_TRIES 3 - -#define DEFAULT_UNITY_BANNER "Welcome to strongSwan - the Linux VPN Solution!\n" - -/** - * Creates a modecfg_attribute_t object - */ -static modecfg_attribute_t *modecfg_attribute_create(configuration_attribute_type_t type, - chunk_t value) -{ - modecfg_attribute_t *this; - - this = malloc_thing(modecfg_attribute_t); - this->type = ((u_int16_t)type) & 0x7FFF; - this->is_tv = FALSE; - this->value = chunk_clone(value); - this->handler = NULL; - - return this; -} - -/** - * Creates a modecfg_attribute_t object coded in TV format - */ -static modecfg_attribute_t *modecfg_attribute_create_tv(configuration_attribute_type_t type, - size_t value) -{ - modecfg_attribute_t *this; - - this = modecfg_attribute_create(type, chunk_empty); - this->value.len = value; - this->is_tv = TRUE; - - return this; -} - -/** - * Destroys a modecfg_attribute_t object - */ -void modecfg_attribute_destroy(modecfg_attribute_t *this) -{ - free(this->value.ptr); - free(this); -} - -/** - * Get attributes to be sent to client - */ -static void get_attributes(connection_t *c, linked_list_t *ca_list) -{ - configuration_attribute_type_t type; - identification_t *client_id; - modecfg_attribute_t *ca; - enumerator_t *enumerator; - chunk_t value; - host_t *vip = NULL, *requested_vip = NULL; - bool want_unity_banner = FALSE; - int family; - -#ifdef CISCO_QUIRKS - /* always send banner in ModeCfg push mode */ - if (ca_list->get_count(ca_list) == 0) - { - want_unity_banner = TRUE; - } -#endif - - /* scan list of requested attributes in ModeCfg pull mode */ - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP6_ADDRESS: - { - int family; - - family = (ca->type == INTERNAL_IP4_ADDRESS) ? AF_INET : AF_INET6; - DESTROY_IF(requested_vip); - requested_vip = (ca->value.len) ? - host_create_from_chunk(family, ca->value, 0) : - host_create_any(family); - plog("peer requested virtual IP %H", requested_vip); - break; - } -#ifdef CISCO_QUIRKS - case UNITY_BANNER: - want_unity_banner = TRUE; - break; -#endif - default: - break; - } - modecfg_attribute_destroy(ca); - } - - if (requested_vip == NULL) - { - requested_vip = host_create_any(AF_INET); - } - - client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - /* if no virtual IP has been assigned yet - acquire one */ - if (c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - if (c->spd.that.pool) - { - vip = hydra->attributes->acquire_address(hydra->attributes, - c->spd.that.pool, client_id, requested_vip); - if (vip) - { - c->spd.that.host_srcip->destroy(c->spd.that.host_srcip); - c->spd.that.host_srcip = vip; - } - } - else - { - plog("no virtual IP found"); - } - } - - requested_vip->destroy(requested_vip); - - /* if we have a virtual IP address - send it */ - if (!c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - vip = c->spd.that.host_srcip; - plog("assigning virtual IP %H to peer", vip); - family = vip->get_family(vip); - ca = modecfg_attribute_create((family == AF_INET) ? - INTERNAL_IP4_ADDRESS : - INTERNAL_IP6_ADDRESS, - vip->get_address(vip)); - ca_list->insert_last(ca_list, ca); - - /* set the remote client subnet to virtual IP */ - c->spd.that.client.addr = *(ip_address*)vip->get_sockaddr(vip); - c->spd.that.client.maskbits = (family == AF_INET) ? 32 : 128; - c->spd.that.has_client = TRUE; - } - - /* assign attributes from registered providers */ - enumerator = hydra->attributes->create_responder_enumerator(hydra->attributes, - c->spd.that.pool, client_id, vip); - while (enumerator->enumerate(enumerator, &type, &value)) - { - ca = modecfg_attribute_create(type, value); - ca_list->insert_last(ca_list, ca); - if (type == UNITY_BANNER) - { - want_unity_banner = FALSE; - } - } - enumerator->destroy(enumerator); - - if (want_unity_banner) - { - ca = modecfg_attribute_create(UNITY_BANNER, - chunk_create(DEFAULT_UNITY_BANNER, - strlen(DEFAULT_UNITY_BANNER))); - ca_list->insert_last(ca_list, ca); - } -} - -/** - * Set srcip and client subnet to internal IP address - */ -static bool set_attributes(connection_t *c, linked_list_t *ca_list) -{ - host_t *vip, *srcip; - modecfg_attribute_t *ca, *ca_handler; - enumerator_t *enumerator; - bool vip_set = FALSE; - - enumerator = ca_list->create_enumerator(ca_list); - while (enumerator->enumerate(enumerator, &ca)) - { - int family = AF_INET6; - attribute_handler_t *handler = NULL; - enumerator_t *e; - - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - family = AF_INET; - /* fall */ - case INTERNAL_IP6_ADDRESS: - if (ca->value.len == 0) - { - vip = host_create_any(family); - } - else - { - /* skip prefix byte in IPv6 payload*/ - if (family == AF_INET6) - { - ca->value.len = 16; - } - vip = host_create_from_chunk(family, ca->value, 0); - } - if (vip) - { - srcip = c->spd.this.host_srcip; - - if (srcip->is_anyaddr(srcip) || srcip->equals(srcip, vip)) - { - plog("setting virtual IP source address to %H", vip); - } - else - { - plog("replacing virtual IP source address %H by %H", - srcip, vip); - } - srcip->destroy(srcip); - c->spd.this.host_srcip = vip; - - /* setting client subnet to vip/32 */ - addrtosubnet((ip_address*)vip->get_sockaddr(vip), - &c->spd.this.client); - setportof(0, &c->spd.this.client.addr); - c->spd.this.has_client = TRUE; - - vip_set = TRUE; - } - continue; - case APPLICATION_VERSION: -#ifdef CISCO_QUIRKS - case UNITY_BANNER: -#endif - if (ca->value.len > 0) - { - DBG(DBG_PARSING | DBG_CONTROLMORE, - DBG_log(" '%.*s'", ca->value.len, ca->value.ptr) - ) - } - break; - default: - break; - } - - /* find the first handler which requested this attribute */ - e = c->requested->create_enumerator(c->requested); - while (e->enumerate(e, &ca_handler)) - { - if (ca_handler->type == ca->type) - { - handler = ca_handler->handler; - break; - } - } - e->destroy(e); - - /* and pass it to the handle function */ - handler = hydra->attributes->handle(hydra->attributes, - c->spd.that.id, handler, ca->type, ca->value); - if (handler) - { - ca_handler = modecfg_attribute_create(ca->type, ca->value); - ca_handler->handler = handler; - - if (c->attributes == NULL) - { - c->attributes = linked_list_create(); - } - c->attributes->insert_last(c->attributes, ca_handler); - } - } - enumerator->destroy(enumerator); - c->requested->destroy_function(c->requested, (void*)modecfg_attribute_destroy); - c->requested = NULL; - return vip_set; -} - -/** - * Register configuration attribute handlers - */ -static void register_attribute_handlers(connection_t *c) -{ - configuration_attribute_type_t type; - modecfg_attribute_t *ca; - chunk_t value; - attribute_handler_t *handler; - enumerator_t *enumerator; - - /* add configuration attributes requested by handlers */ - if (c->requested == NULL) - { - c->requested = linked_list_create(); - } - enumerator = hydra->attributes->create_initiator_enumerator( - hydra->attributes,c->spd.that.id, c->spd.this.host_srcip); - while (enumerator->enumerate(enumerator, &handler, &type, &value)) - { - ca = modecfg_attribute_create(type, value); - ca->handler = handler; - c->requested->insert_last(c->requested, ca); - } - enumerator->destroy(enumerator); -} - -/** - * Compute HASH of Mode Config. - */ -static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof, - const struct state *st) -{ - chunk_t msgid_chunk = chunk_from_thing(st->st_msgid); - chunk_t msg_chunk = { start, roof - start }; - size_t prf_block_size; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG(DBG_CRYPT, - DBG_log("ModeCfg HASH computed:"); - DBG_dump("", dest, prf_block_size) - ) - return prf_block_size; -} - - -/** - * Generate an IKE message containing ModeCfg information (eg: IP, DNS, WINS) - */ -static stf_status modecfg_build_msg(struct state *st, pb_stream *rbody, - u_int16_t msg_type, linked_list_t *ca_list, - u_int16_t ap_id) -{ - u_char *r_hash_start, *r_hashval; - struct isakmp_mode_attr attrh; - struct isakmp_attribute attr; - pb_stream strattr,attrval; - enumerator_t *enumerator; - modecfg_attribute_t *ca; - - START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR); - - attrh.isama_np = ISAKMP_NEXT_NONE; - attrh.isama_type = msg_type; - attrh.isama_identifier = ap_id; - - if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr)) - { - return STF_INTERNAL_ERROR; - } - - enumerator = ca_list->create_enumerator(ca_list); - while (enumerator->enumerate(enumerator, &ca)) - { - DBG(DBG_CONTROLMORE, - DBG_log("building %N attribute", configuration_attribute_type_names, ca->type) - ) - if (ca->is_tv) - { - attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TV; - attr.isaat_lv = ca->value.len; - out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); - } - else - { - char buf[BUF_LEN]; - - attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TLV; - out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); - snprintf(buf, BUF_LEN, "%N", configuration_attribute_type_names, ca->type); - out_raw(ca->value.ptr, ca->value.len, &attrval, buf); - } - close_output_pbs(&attrval); - } - enumerator->destroy(enumerator); - close_output_pbs(&strattr); - - modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); - close_message(rbody); - encrypt_message(rbody, st); - return STF_OK; -} - -/** - * Send ModeCfg message - */ -static stf_status modecfg_send_msg(struct state *st, int isama_type, - linked_list_t *ca_list) -{ - pb_stream msg; - pb_stream rbody; - char buf[BUF_LEN]; - - /* set up attr */ - init_pbs(&msg, buf, sizeof(buf), "ModeCfg msg buffer"); - - /* this is the beginning of a new exchange */ - st->st_msgid = generate_msgid(st); - init_phase2_iv(st, &st->st_msgid); - - /* HDR out */ - { - struct isakmp_hdr hdr; - - zero(&hdr); /* default to 0 */ - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - hdr.isa_msgid = st->st_msgid; - - if (!out_struct(&hdr, &isakmp_hdr_desc, &msg, &rbody)) - { - return STF_INTERNAL_ERROR; - } - } - - /* ATTR out with isama_id of 0 */ - modecfg_build_msg(st, &rbody, isama_type, ca_list, 0); - - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(msg.start, pbs_offset(&msg)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* Transmit */ - send_packet(st, "ModeCfg msg"); - - if (st->st_event->ev_type != EVENT_RETRANSMIT) - { - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - } - return STF_OK; -} - -/** - * Parse a ModeCfg attribute payload - */ -static stf_status modecfg_parse_attributes(pb_stream *attrs, linked_list_t *ca_list) -{ - struct isakmp_attribute attr; - pb_stream strattr; - u_int16_t attr_type; - u_int16_t attr_len; - chunk_t attr_chunk; - modecfg_attribute_t *ca; - - while (pbs_left(attrs) >= sizeof(struct isakmp_attribute)) - { - if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr)) - { - return STF_FAIL; - } - attr_type = attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK; - attr_len = attr.isaat_lv; - DBG(DBG_CONTROLMORE, - DBG_log("processing %N attribute", - configuration_attribute_type_names, attr_type) - ) - - switch (attr_type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: - if (attr_len != 4 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP4_SUBNET: - if (attr_len != 8 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_NETMASK: - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - case INTERNAL_IP6_DHCP: - if (attr_len != 16 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_ADDRESS: - if (attr_len != 17 && attr_len != 16 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_SUBNET: - if (attr_len != 17 && attr_len != 0) - { - goto error; - } - break; - case SUPPORTED_ATTRIBUTES: - if (attr_len % 2) - { - goto error; - } - break; - case APPLICATION_VERSION: - break; - /* XAUTH attributes */ - case XAUTH_TYPE: - case XAUTH_STATUS: - case XAUTH_USER_NAME: - case XAUTH_USER_PASSWORD: - case XAUTH_PASSCODE: - case XAUTH_MESSAGE: - case XAUTH_CHALLENGE: - case XAUTH_DOMAIN: - case XAUTH_NEXT_PIN: - case XAUTH_ANSWER: - break; - /* Microsoft attributes */ - case INTERNAL_IP4_SERVER: - case INTERNAL_IP6_SERVER: - break; - /* Cisco Unity attributes */ - case UNITY_BANNER: - case UNITY_SAVE_PASSWD: - case UNITY_DEF_DOMAIN: - case UNITY_SPLITDNS_NAME: - case UNITY_SPLIT_INCLUDE: - case UNITY_NATT_PORT: - case UNITY_LOCAL_LAN: - case UNITY_PFS: - case UNITY_FW_TYPE: - case UNITY_BACKUP_SERVERS: - case UNITY_DDNS_HOSTNAME: - break; - default: - plog("unknown attribute type (%u)", attr_type); - continue; - } - - /* add attribute */ - if (attr.isaat_af_type & ISAKMP_ATTR_AF_TV) - { - ca = modecfg_attribute_create_tv(attr_type, attr_len); - } - else - { - attr_chunk = chunk_create(strattr.cur, attr_len); - ca = modecfg_attribute_create(attr_type, attr_chunk); - } - ca_list->insert_last(ca_list, ca); - } - return STF_OK; - -error: - plog("%N attribute has invalid size of %u octets", - configuration_attribute_type_names, attr_type, attr_len); - return STF_FAIL; -} - -/** - * Parse a ModeCfg message - */ -static stf_status modecfg_parse_msg(struct msg_digest *md, int isama_type, - u_int16_t *isama_id, linked_list_t *ca_list) -{ - modecfg_attribute_t *ca; - struct state *const st = md->st; - struct payload_digest *p; - stf_status stat; - - st->st_msgid = md->hdr.isa_msgid; - - CHECK_QUICK_HASH(md, modecfg_hash(hash_val, hash_pbs->roof, - md->message_pbs.roof, st), "MODECFG-HASH", "ISAKMP_CFG_MSG"); - - /* process the ModeCfg payloads received */ - for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next) - { - if (p->payload.attribute.isama_type == isama_type) - { - *isama_id = p->payload.attribute.isama_identifier; - - stat = modecfg_parse_attributes(&p->pbs, ca_list); - if (stat == STF_OK) - { - /* return with a valid set of attributes */ - return STF_OK; - } - } - else - { - plog("expected %s, got %s instead (ignored)" - , enum_name(&attr_msg_type_names, isama_type) - , enum_name(&attr_msg_type_names, p->payload.attribute.isama_type)); - - stat = modecfg_parse_attributes(&p->pbs, ca_list); - } - - /* abort if a parsing error occurred */ - if (stat != STF_OK) - { - ca_list->destroy_function(ca_list, (void*)modecfg_attribute_destroy); - return stat; - } - - /* discard the parsed attributes and look for another payload */ - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) {} - } - return STF_IGNORE; -} - -/** - * Used in ModeCfg pull mode on the client (initiator) - * called in demux.c - * client -> CFG_REQUEST - * STF_OK transitions to STATE_MODE_CFG_I1 - */ -stf_status modecfg_send_request(struct state *st) -{ - connection_t *c = st->st_connection; - stf_status stat; - modecfg_attribute_t *ca; - enumerator_t *enumerator; - int family; - chunk_t value; - host_t *vip; - linked_list_t *ca_list = linked_list_create(); - - vip = c->spd.this.host_srcip; - value = vip->is_anyaddr(vip) ? chunk_empty : vip->get_address(vip); - family = vip->get_family(vip); - ca = modecfg_attribute_create((family == AF_INET) ? - INTERNAL_IP4_ADDRESS : INTERNAL_IP6_ADDRESS, - value); - ca_list->insert_last(ca_list, ca); - - register_attribute_handlers(c); - enumerator = c->requested->create_enumerator(c->requested); - while (enumerator->enumerate(enumerator, &ca)) - { - ca = modecfg_attribute_create(ca->type, chunk_empty); - ca_list->insert_last(ca_list, ca); - } - enumerator->destroy(enumerator); - - plog("sending ModeCfg request"); - - st->st_state = STATE_MODE_CFG_I1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_modecfg.started = TRUE; - } - return stat; -} - -/** - * Used in ModeCfg pull mode on the server (responder) - * called in demux.c from STATE_MODE_CFG_R0 - * server <- CFG_REQUEST - * server -> CFG_REPLY - * STF_OK transitions to STATE_MODE_CFG_R0 - */ -stf_status modecfg_inR0(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg request"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - /* build the CFG_REPLY */ - get_attributes(st->st_connection, ca_list); - - plog("sending ModeCfg reply"); - - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - - if (stat_build != STF_OK) - { - return stat_build; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used in ModeCfg pull mode on the client (initiator) - * called in demux.c from STATE_MODE_CFG_I1 - * client <- CFG_REPLY - * STF_OK transitions to STATE_MODE_CFG_I2 - */ -stf_status modecfg_inI1(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg reply"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - st->st_modecfg.vars_set = set_attributes(st->st_connection, ca_list); - st->st_msgid = 0; - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - return STF_OK; -} - -/** - * Used in ModeCfg push mode on the server (responder) - * called in demux.c - * server -> CFG_SET - * STF_OK transitions to STATE_MODE_CFG_R3 - */ -stf_status modecfg_send_set(struct state *st) -{ - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - - plog("sending ModeCfg set"); - - get_attributes(st->st_connection, ca_list); - st->st_state = STATE_MODE_CFG_R3; - stat = modecfg_send_msg(st, ISAKMP_CFG_SET, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_modecfg.started = TRUE; - } - return stat; -} - -/** - * Used in ModeCfg push mode on the client (initiator) - * called in demux.c from STATE_MODE_CFG_I0 - * client <- CFG_SET - * client -> CFG_ACK - * STF_OK transitions to STATE_MODE_CFG_I3 - */ -stf_status modecfg_inI0(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - linked_list_t *ca_list, *ca_ack_list; - - plog("parsing ModeCfg set"); - - ca_list = linked_list_create(); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - register_attribute_handlers(st->st_connection); - st->st_modecfg.vars_set = set_attributes(st->st_connection, ca_list); - - /* prepare ModeCfg ack which sends zero length attributes */ - ca_ack_list = linked_list_create(); - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case APPLICATION_VERSION: - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: -#ifdef CISCO_QUIRKS - case UNITY_BANNER: -#endif - /* supported attributes */ - ca->value.len = 0; - ca_ack_list->insert_last(ca_ack_list, ca); - break; - default: - /* unsupportd attributes */ - modecfg_attribute_destroy(ca); - } - } - ca_list->destroy(ca_list); - - plog("sending ModeCfg ack"); - - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, - ca_ack_list, isama_id); - ca_ack_list->destroy_function(ca_ack_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used in ModeCfg push mode on the server (responder) - * called in demux.c from STATE_MODE_CFG_R3 - * server <- CFG_ACK - * STF_OK transitions to STATE_MODE_CFG_R4 - */ -stf_status modecfg_inR3(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg ack"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat != STF_OK) - { - return stat; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c - * server -> CFG_REQUEST - * STF_OK transitions to STATE_XAUTH_R1 - */ -stf_status xauth_send_request(struct state *st) -{ - stf_status stat; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - ca = modecfg_attribute_create(XAUTH_USER_NAME, chunk_empty); - ca_list->insert_last(ca_list, ca); - ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, chunk_empty); - ca_list->insert_last(ca_list, ca); - - plog("sending XAUTH request"); - st->st_state = STATE_XAUTH_R1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_xauth.started = TRUE; - } - return stat; -} - -/** - * Used on the XAUTH client (initiator) - * called in demux.c from STATE_XAUTH_I0 - * client <- CFG_REQUEST - * client -> CFG_REPLY - * STF_OK transitions to STATE_XAUTH_I1 - */ -stf_status xauth_inI0(struct msg_digest *md) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - bool xauth_user_name_present = FALSE; - bool xauth_user_password_present = FALSE; - bool xauth_type_present = FALSE; - chunk_t xauth_user_name, xauth_user_password; - identification_t *user_id; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH request"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case XAUTH_TYPE: - if (ca->value.len != XAUTH_TYPE_GENERIC) - { - plog("xauth type %s is not supported", - enum_name(&xauth_type_names, ca->value.len)); - stat = STF_FAIL; - } - else - { - xauth_type_present = TRUE; - } - break; - case XAUTH_USER_NAME: - xauth_user_name_present = TRUE; - break; - case XAUTH_USER_PASSWORD: - xauth_user_password_present = TRUE; - break; - case XAUTH_MESSAGE: - if (ca->value.len) - { - DBG(DBG_PARSING | DBG_CONTROLMORE, - DBG_log(" '%.*s'", ca->value.len, ca->value.ptr) - ) - } - break; - default: - break; - } - modecfg_attribute_destroy(ca); - } - - if (!xauth_user_name_present) - { - plog("user name attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - if (!xauth_user_password_present) - { - plog("user password attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - - /* prepare XAUTH reply */ - if (stat == STF_OK) - { - /* get user credentials using a plugin function */ - if (!pluto->xauth->get_secret(pluto->xauth, c, &xauth_user_password)) - { - plog("xauth user credentials not found"); - stat = STF_FAIL; - } - } - if (stat == STF_OK) - { - /* insert xauth type if present */ - if (xauth_type_present) - { - ca = modecfg_attribute_create_tv(XAUTH_TYPE, XAUTH_TYPE_GENERIC); - ca_list->insert_last(ca_list, ca); - } - - /* insert xauth user name */ - user_id = (c->xauth_identity) ? c->xauth_identity : c->spd.this.id; - xauth_user_name = user_id->get_encoding(user_id); - DBG(DBG_CONTROL, - DBG_log("my xauth user name is '%.*s'", xauth_user_name.len, - xauth_user_name.ptr) - ) - ca = modecfg_attribute_create(XAUTH_USER_NAME, xauth_user_name); - ca_list->insert_last(ca_list, ca); - - /* insert xauth user password */ - DBG(DBG_PRIVATE, - DBG_log("my xauth user password is '%.*s'", xauth_user_password.len, - xauth_user_password.ptr) - ) - ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, xauth_user_password); - ca_list->insert_last(ca_list, ca); - chunk_clear(&xauth_user_password); - } - else - { - ca = modecfg_attribute_create_tv(XAUTH_STATUS, XAUTH_STATUS_FAIL); - ca_list->insert_last(ca_list, ca); - } - - plog("sending XAUTH reply"); - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - if (stat == STF_OK) - { - st->st_xauth.started = TRUE; - st->st_msgid = 0; - return STF_OK; - } - else - { - /* send XAUTH reply msg and then delete ISAKMP SA */ - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - send_packet(st, "XAUTH reply msg"); - delete_state(st); - return STF_IGNORE; - } -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c from STATE_XAUTH_R1 - server <- CFG_REPLY - server -> CFG_SET - STF_OK transitions to STATE_XAUTH_R2 - */ -stf_status xauth_inR1(struct msg_digest *md) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - u_int16_t isama_id; - stf_status stat, stat_build; - chunk_t xauth_user_name, xauth_user_password; - int xauth_status = XAUTH_STATUS_OK; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH reply"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - /* initialize xauth_secret */ - xauth_user_name = chunk_empty; - xauth_user_password = chunk_empty; - - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case XAUTH_STATUS: - xauth_status = ca->value.len; - break; - case XAUTH_USER_NAME: - xauth_user_name = chunk_clone(ca->value); - break; - case XAUTH_USER_PASSWORD: - xauth_user_password = chunk_clone(ca->value); - break; - default: - break; - } - modecfg_attribute_destroy(ca); - } - /* did the client return an XAUTH FAIL status? */ - if (xauth_status == XAUTH_STATUS_FAIL) - { - plog("received FAIL status in XAUTH reply"); - - /* client is not able to do XAUTH, delete ISAKMP SA */ - free(xauth_user_name.ptr); - free(xauth_user_password.ptr); - delete_state(st); - ca_list->destroy(ca_list); - return STF_IGNORE; - } - - /* check XAUTH reply */ - if (xauth_user_name.ptr == NULL) - { - plog("user name attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else if (xauth_user_password.ptr == NULL) - { - plog("user password attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else - { - DBG(DBG_CONTROL, - DBG_log("peer xauth user name is '%.*s'", xauth_user_name.len, - xauth_user_name.ptr) - ) - DESTROY_IF(c->xauth_identity); - c->xauth_identity = identification_create_from_data(xauth_user_name); - - DBG(DBG_PRIVATE, - DBG_log("peer xauth user password is '%.*s'", xauth_user_password.len, - xauth_user_password.ptr) - ) - /* verify the user credentials using a plugin function */ - st->st_xauth.status = pluto->xauth->verify_secret(pluto->xauth, c, - xauth_user_password); - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - } - chunk_clear(&xauth_user_name); - chunk_clear(&xauth_user_password); - - plog("sending XAUTH status"); - xauth_status = (st->st_xauth.status) ? XAUTH_STATUS_OK : XAUTH_STATUS_FAIL; - ca = modecfg_attribute_create_tv(XAUTH_STATUS, xauth_status); - ca_list->insert_last(ca_list, ca); - stat_build = modecfg_send_msg(st, ISAKMP_CFG_SET, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - return STF_OK; -} - -/** - * Used on the XAUTH client (initiator) - * called in demux.c from STATE_XAUTH_I1 - * client <- CFG_SET - * client -> CFG_ACK - * STF_OK transitions to STATE_XAUTH_I2 - */ -stf_status xauth_inI1(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH status"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); - if (stat != STF_OK) - { - /* notification payload - not exactly the right choice, but okay */ - md->note = ISAKMP_ATTRIBUTES_NOT_SUPPORTED; - return stat; - } - - st->st_xauth.status = FALSE; - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - if (ca->type == XAUTH_STATUS) - { - st->st_xauth.status = (ca->value.len == XAUTH_STATUS_OK); - } - modecfg_attribute_destroy(ca); - } - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - - plog("sending XAUTH ack"); - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, ca_list, isama_id); - ca_list->destroy(ca_list); - - if (stat_build != STF_OK) - { - return stat_build; - } - if (st->st_xauth.status) - { - st->st_msgid = 0; - return STF_OK; - } - else - { - /* send XAUTH ack msg and then delete ISAKMP SA */ - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - send_packet(st, "XAUTH ack msg"); - delete_state(st); - return STF_IGNORE; - } -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c from STATE_XAUTH_R2 - * server <- CFG_ACK - * STF_OK transitions to STATE_XAUTH_R3 - */ -stf_status xauth_inR2(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH ack"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - st->st_msgid = 0; - if (st->st_xauth.status) - { - return STF_OK; - } - else - { - delete_state(st); - return STF_IGNORE; - } - -} diff --git a/src/pluto/modecfg.h b/src/pluto/modecfg.h deleted file mode 100644 index 7adf18682..000000000 --- a/src/pluto/modecfg.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Mode Config related functions - * Copyright (C) 2001-2002 Colubris Networks - * Copyright (C) 2003-2004 Xelerance Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _MODECFG_H -#define _MODECFG_H - -#include -#include - -#include "state.h" -#include "demux.h" - -typedef struct modecfg_attribute_t modecfg_attribute_t; - -/** - * Defines a modecfg_attribute_t object. - */ -struct modecfg_attribute_t { - /** - * Type of the attribute. - */ - u_int16_t type; - - /** - * Attribute is coded as TV - */ - bool is_tv; - - /** - * Attribute value as chunk. - */ - chunk_t value; - - /** - * Attribute handler. - */ - attribute_handler_t *handler; -}; - -/* Destroys a modecfg_attribute_t object */ -extern void modecfg_attribute_destroy(modecfg_attribute_t *this); - -/* ModeConfig pull mode start function */ -extern stf_status modecfg_send_request(struct state *st); - -/* ModeConfig pull mode state transition functions */ -extern stf_status modecfg_inR0(struct msg_digest *md); -extern stf_status modecfg_inI1(struct msg_digest *md); - -/* ModeConfig push mode start function */ -extern stf_status modecfg_send_set(struct state *st); - -/* ModeConfig push mode state transition functions */ -extern stf_status modecfg_inI0(struct msg_digest *md); -extern stf_status modecfg_inR3(struct msg_digest *md); - -/* XAUTH start function */ -extern stf_status xauth_send_request(struct state *st); - -/* XAUTH state transition funcgtions */ -extern stf_status xauth_inI0(struct msg_digest *md); -extern stf_status xauth_inR1(struct msg_digest *md); -extern stf_status xauth_inI1(struct msg_digest *md); -extern stf_status xauth_inR2(struct msg_digest *md); - -#endif /* _MODECFG_H */ diff --git a/src/pluto/myid.c b/src/pluto/myid.c deleted file mode 100644 index c90d14ef8..000000000 --- a/src/pluto/myid.c +++ /dev/null @@ -1,121 +0,0 @@ -/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) - * Copyright (C) 1999-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says defines this */ -# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */ -#endif - -#include - -#include - -#include "myid.h" -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "connections.h" -#include "packet.h" -#include "whack.h" - -enum myid_state myid_state = MYID_UNKNOWN; - -identification_t *myids[MYID_SPECIFIED+1]; /* %myid */ - -/** - * Fills in myid from environment variable IPSECmyid or defaultrouteaddr - */ -void init_myid(void) -{ - myid_state = MYID_UNKNOWN; - { - enum myid_state s; - - for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) - { - myids[s] = identification_create_from_string("%any"); - } - } - set_myid(MYID_SPECIFIED, getenv("IPSECmyid")); - set_myid(MYID_IP, getenv("defaultrouteaddr")); - set_myFQDN(); -} - -/** - * Free myid module - */ -void free_myid(void) -{ - enum myid_state s; - - for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) - { - DESTROY_IF(myids[s]); - } -} - -void set_myid(enum myid_state s, char *idstr) -{ - if (idstr) - { - myids[s]->destroy(myids[s]); - myids[s] = identification_create_from_string(idstr); - if (s == MYID_SPECIFIED) - { - myid_state = MYID_SPECIFIED; - } - } -} - -void set_myFQDN(void) -{ - char FQDN[HOST_NAME_MAX + 1]; - int r = gethostname(FQDN, sizeof(FQDN)); - size_t len; - - if (r != 0) - { - log_errno((e, "gethostname() failed in set_myFQDN")); - } - else - { - FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */ - len = strlen(FQDN); - - if (len > 0 && FQDN[len-1] == '.') - { - /* nuke trailing . */ - FQDN[len-1] = '\0'; - } - if (!strcaseeq(FQDN, "localhost.localdomain")) - { - myids[MYID_HOSTNAME]->destroy(myids[MYID_HOSTNAME]); - myids[MYID_HOSTNAME] = identification_create_from_string(FQDN); - } - } -} - -void show_myid_status(void) -{ - whack_log(RC_COMMENT, "%%myid = '%Y'", myids[myid_state]); -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/myid.h b/src/pluto/myid.h deleted file mode 100644 index 012a34968..000000000 --- a/src/pluto/myid.h +++ /dev/null @@ -1,38 +0,0 @@ -/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) - * Copyright (C) 1999-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _MYID_H -#define _MYID_H - -#include - -extern void init_myid(void); -extern void free_myid(void); - -enum myid_state { - MYID_UNKNOWN, /* not yet figured out */ - MYID_HOSTNAME, /* our current hostname */ - MYID_IP, /* our default IP address */ - MYID_SPECIFIED /* as specified by ipsec.conf */ -}; - -extern enum myid_state myid_state; -extern identification_t* myids[MYID_SPECIFIED+1]; /* %myid */ -extern void set_myid(enum myid_state s, char *); -extern void show_myid_status(void); -extern void set_myFQDN(void); - -#define resolve_myid(id) ((id)->get_type(id) == ID_MYID? myids[myid_state] : (id)) - -#endif /* _MYID_H */ diff --git a/src/pluto/nat_traversal.c b/src/pluto/nat_traversal.c deleted file mode 100644 index 28be76825..000000000 --- a/src/pluto/nat_traversal.c +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2002-2005 Mathieu Lafon - * Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* used only if MSG_NOSIGNAL not defined */ -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "server.h" -#include "state.h" -#include "connections.h" -#include "packet.h" -#include "demux.h" -#include "kernel.h" -#include "whack.h" -#include "timer.h" -#include "cookie.h" -#include "crypto.h" -#include "vendor.h" -#include "ike_alg.h" -#include "nat_traversal.h" - -/* #define FORCE_NAT_TRAVERSAL */ -#define NAT_D_DEBUG -#define NAT_T_SUPPORT_LAST_DRAFTS - -#ifndef SOL_UDP -#define SOL_UDP 17 -#endif - -#ifndef UDP_ESPINUDP -#define UDP_ESPINUDP 100 -#endif - -#define DEFAULT_KEEP_ALIVE_PERIOD 20 - -#ifdef _IKE_ALG_H -/* Alg patch: hash_digest_len -> hash_digest_size */ -#define hash_digest_len hash_digest_size -#endif - -bool nat_traversal_enabled = FALSE; -bool nat_traversal_support_non_ike = FALSE; -bool nat_traversal_support_port_floating = FALSE; - -static unsigned int _kap = 0; -static unsigned int _ka_evt = 0; -static bool _force_ka = 0; - -static const char *natt_version = "0.6c"; - -void init_nat_traversal (bool activate, unsigned int keep_alive_period, - bool fka, bool spf) -{ - nat_traversal_enabled = activate; - nat_traversal_support_non_ike = activate; -#ifdef NAT_T_SUPPORT_LAST_DRAFTS - nat_traversal_support_port_floating = activate ? spf : FALSE; -#endif - _force_ka = fka; - _kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD; - plog(" including NAT-Traversal patch (Version %s)%s%s%s" - , natt_version, activate ? "" : " [disabled]" - , activate & fka ? " [Force KeepAlive]" : "" - , activate & !spf ? " [Port Floating disabled]" : ""); -} - -static void disable_nat_traversal (int type) -{ - if (type == ESPINUDP_WITH_NON_IKE) - nat_traversal_support_non_ike = FALSE; - else - nat_traversal_support_port_floating = FALSE; - - if (!nat_traversal_support_non_ike && - !nat_traversal_support_port_floating) - nat_traversal_enabled = FALSE; -} - -static void _natd_hash(const struct hash_desc *oakley_hasher, char *hash, - u_int8_t *icookie, u_int8_t *rcookie, - const ip_address *ip, u_int16_t port) -{ - if (is_zero_cookie(icookie)) - { - DBG_log("_natd_hash: Warning, icookie is zero !!"); - } - if (is_zero_cookie(rcookie)) - { - DBG_log("_natd_hash: Warning, rcookie is zero !!"); - } - - /** - * draft-ietf-ipsec-nat-t-ike-01.txt - * - * HASH = HASH(CKY-I | CKY-R | IP | Port) - * - * All values in network order - */ - { - chunk_t icookie_chunk = { icookie, COOKIE_SIZE }; - chunk_t rcookie_chunk = { rcookie, COOKIE_SIZE }; - chunk_t port_chunk = chunk_from_thing(port); - chunk_t addr_chunk; - hash_algorithm_t hash_alg; - hasher_t *hasher; - size_t hash_size; - - hash_alg = oakley_to_hash_algorithm(oakley_hasher->algo_id); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - hasher->get_hash(hasher, icookie_chunk, NULL); - hasher->get_hash(hasher, rcookie_chunk, NULL); - switch (addrtypeof(ip)) - { - case AF_INET: - addr_chunk = chunk_from_thing(ip->u.v4.sin_addr.s_addr); - break; - case AF_INET6: - addr_chunk = chunk_from_thing(ip->u.v6.sin6_addr.s6_addr); - break; - default: - addr_chunk = chunk_empty; /* should never occur */ - } - hasher->get_hash(hasher, addr_chunk, NULL); - hasher->get_hash(hasher, port_chunk, hash); - hash_size = hasher->get_hash_size(hasher); - hasher->destroy(hasher); -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_dump_chunk("_natd_hash: icookie=", icookie_chunk); - DBG_dump_chunk("_natd_hash: rcookie=", rcookie_chunk); - DBG_dump_chunk("_natd_hash: ip=", addr_chunk); - DBG_log("_natd_hash: port=%d", port); - DBG_dump("_natd_hash: hash=", hash, hash_size); - ) -#endif - } -} - -/* Add NAT-Traversal VIDs (supported ones) - * used when we are Initiator - */ -bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs) -{ - bool r = TRUE; - - if (nat_traversal_support_port_floating) - { - u_int8_t last_np = nat_traversal_support_non_ike ? - ISAKMP_NEXT_VID : np; - - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_RFC); - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_03); - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_02); - if (r) - r = out_vendorid(last_np, outs, VID_NATT_IETF_02_N); - } - if (nat_traversal_support_non_ike) - { - if (r) - r = out_vendorid(np, outs, VID_NATT_IETF_00); - } - return r; -} - -u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid) -{ - switch (nat_t_vid) - { - case VID_NATT_IETF_00: - return LELEM(NAT_TRAVERSAL_IETF_00_01); - case VID_NATT_IETF_02: - case VID_NATT_IETF_02_N: - case VID_NATT_IETF_03: - return LELEM(NAT_TRAVERSAL_IETF_02_03); - case VID_NATT_RFC: - return LELEM(NAT_TRAVERSAL_RFC); - } - return 0; -} - -void nat_traversal_natd_lookup(struct msg_digest *md) -{ - char hash[MAX_DIGEST_LEN]; - struct payload_digest *p; - struct state *st = md->st; - int i; - - if (!st || !md->iface || !st->st_oakley.hasher) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return; - } - - /** Count NAT-D **/ - for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++); - - /* - * We need at least 2 NAT-D (1 for us, many for peer) - */ - if (i < 2) - { - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negotiation", i); - st->nat_traversal = 0; - return; - } - - /* - * First one with my IP & port - */ - p = md->chain[ISAKMP_NEXT_NATD_RFC]; - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie, - &(md->iface->addr), ntohs(st->st_connection->spd.this.host_port)); - - if (!(pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len && - memeq(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len))) - { -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_log("NAT_TRAVERSAL_NAT_BHND_ME"); - DBG_dump("expected NAT-D:", hash - , st->st_oakley.hasher->hash_digest_len); - DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); - ) -#endif - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); - } - - /* - * The others with sender IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie, - &(md->sender), ntohs(md->sender_port)); - for (p = p->next, i=0 ; p != NULL; p = p->next) - { - if (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len && - memeq(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)) - { - i++; - } - } - if (!i) - { -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER"); - DBG_dump("expected NAT-D:", hash - , st->st_oakley.hasher->hash_digest_len); - p = md->chain[ISAKMP_NEXT_NATD_RFC]; - for (p = p->next, i=0 ; p != NULL; p = p->next) - { - DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); - } - ) -#endif - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); - } -#ifdef FORCE_NAT_TRAVERSAL - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); -#endif -} - -bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, - struct msg_digest *md) -{ - char hash[MAX_DIGEST_LEN]; - struct state *st = md->st; - - if (!st || !st->st_oakley.hasher) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return FALSE; - } - - DBG(DBG_EMITTING, - DBG_log("sending NATD payloads") - ) - - /* - * First one with sender IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, - is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie, - &(md->sender), -#ifdef FORCE_NAT_TRAVERSAL - 0 -#else - ntohs(md->sender_port) -#endif - ); - if (!out_generic_raw((st->nat_traversal & NAT_T_WITH_RFC_VALUES - ? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), &isakmp_nat_d, outs, - hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")) - { - return FALSE; - } - - /* - * Second one with my IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, - is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie, - &(md->iface->addr), -#ifdef FORCE_NAT_TRAVERSAL - 0 -#else - ntohs(st->st_connection->spd.this.host_port) -#endif - ); - return (out_generic_raw(np, &isakmp_nat_d, outs, - hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")); -} - -/* - * nat_traversal_natoa_lookup() - * - * Look for NAT-OA in message - */ -void nat_traversal_natoa_lookup(struct msg_digest *md) -{ - struct payload_digest *p; - struct state *st = md->st; - int i; - ip_address ip; - - if (!st || !md->iface) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return; - } - - /* Initialize NAT-OA */ - anyaddr(AF_INET, &st->nat_oa); - - /* Count NAT-OA **/ - for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++); - - DBG(DBG_NATT, - DBG_log("NAT-Traversal: received %d NAT-OA.", i) - ) - - if (i == 0) - return; - - if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " - "ignored because peer is not NATed", i); - return; - } - - if (i > 1) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " - "using first, ignoring others", i); - } - - /* Take first */ - p = md->chain[ISAKMP_NEXT_NATOA_RFC]; - - DBG(DBG_PARSING, - DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs)); - ); - - switch (p->payload.nat_oa.isanoa_idtype) - { - case ID_IPV4_ADDR: - if (pbs_left(&p->pbs) == sizeof(struct in_addr)) - { - initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET, &ip); - } - else - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA " - "with invalid IP size (%d)", (int)pbs_left(&p->pbs)); - return; - } - break; - case ID_IPV6_ADDR: - if (pbs_left(&p->pbs) == sizeof(struct in6_addr)) - { - initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip); - } - else - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA " - "with invalid IP size (%d)", (int)pbs_left(&p->pbs)); - return; - } - break; - default: - loglog(RC_LOG_SERIOUS, "NAT-Traversal: " - "invalid ID Type (%d) in NAT-OA - ignored", - p->payload.nat_oa.isanoa_idtype); - return; - } - - DBG(DBG_NATT, - { - char ip_t[ADDRTOT_BUF]; - addrtot(&ip, 0, ip_t, sizeof(ip_t)); - - DBG_log("received NAT-OA: %s", ip_t); - } - ) - - if (isanyaddr(&ip)) - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA..."); - else - st->nat_oa = ip; -} - -bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs, - struct state *st) -{ - struct isakmp_nat_oa natoa; - pb_stream pbs; - unsigned char ip_val[sizeof(struct in6_addr)]; - size_t ip_len = 0; - ip_address *ip; - - if ((!st) || (!st->st_connection)) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return FALSE; - } - ip = &(st->st_connection->spd.this.host_addr); - - memset(&natoa, 0, sizeof(natoa)); - natoa.isanoa_np = np; - - switch (addrtypeof(ip)) - { - case AF_INET: - ip_len = sizeof(ip->u.v4.sin_addr.s_addr); - memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len); - natoa.isanoa_idtype = ID_IPV4_ADDR; - break; - case AF_INET6: - ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr); - memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len); - natoa.isanoa_idtype = ID_IPV6_ADDR; - break; - default: - loglog(RC_LOG_SERIOUS, "NAT-Traversal: " - "invalid addrtypeof()=%d", addrtypeof(ip)); - return FALSE; - } - - if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs)) - return FALSE; - - if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA")) - return FALSE; - - DBG(DBG_NATT, - DBG_dump("NAT-OA (S):", ip_val, ip_len) - ) - - close_output_pbs(&pbs); - return TRUE; -} - -void nat_traversal_show_result (u_int32_t nt, u_int16_t sport) -{ - const char *mth = NULL, *rslt = NULL; - - switch (nt & NAT_TRAVERSAL_METHOD) - { - case LELEM(NAT_TRAVERSAL_IETF_00_01): - mth = natt_type_bitnames[0]; - break; - case LELEM(NAT_TRAVERSAL_IETF_02_03): - mth = natt_type_bitnames[1]; - break; - case LELEM(NAT_TRAVERSAL_RFC): - mth = natt_type_bitnames[2]; - break; - } - - switch (nt & NAT_T_DETECTED) - { - case 0: - rslt = "no NAT detected"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_ME): - rslt = "i am NATed"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER): - rslt = "peer is NATed"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER): - rslt = "both are NATed"; - break; - } - - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: Result using %s: %s", - mth ? mth : "unknown method", - rslt ? rslt : "unknown result" - ); - - if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)) - && (sport == IKE_UDP_PORT) - && ((nt & NAT_T_WITH_PORT_FLOATING)==0)) - { - loglog(RC_LOG_SERIOUS, - "Warning: peer is NATed but source port is still udp/%d. " - "Ipsec-passthrough NAT device suspected -- NAT-T may not work.", - IKE_UDP_PORT - ); - } -} - -int nat_traversal_espinudp_socket (int sk, u_int32_t type) -{ - int r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type)); - - if (r < 0 && errno == ENOPROTOOPT) - { - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: ESPINUDP(%d) not supported by kernel -- " - "NAT-T disabled", type); - disable_nat_traversal(type); - } - return r; -} - -void nat_traversal_new_ka_event (void) -{ - if (_ka_evt) - return; /* event already scheduled */ - - event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL); - _ka_evt = 1; -} - -static void nat_traversal_send_ka (struct state *st) -{ - static unsigned char ka_payload = 0xff; - chunk_t sav; - - DBG(DBG_NATT, - DBG_log("ka_event: send NAT-KA to %s:%d", - ip_str(&st->st_connection->spd.that.host_addr), - st->st_connection->spd.that.host_port); - ) - - /* save state chunk */ - sav = st->st_tpacket; - - /* send keep alive */ - st->st_tpacket = chunk_create(&ka_payload, 1); - send_packet(st, "NAT-T Keep Alive"); - - /* restore state chunk */ - st->st_tpacket = sav; -} - -/** - * Find ISAKMP States with NAT-T and send keep-alive - */ -static void nat_traversal_ka_event_state (struct state *st, void *data) -{ - unsigned int *_kap_st = (unsigned int *)data; - const connection_t *c = st->st_connection; - - if (!c) - return; - - if ((st->st_state == STATE_MAIN_R3 || st->st_state == STATE_MAIN_I4) - && (st->nat_traversal & NAT_T_DETECTED) - && ((st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka)) - { - /* - * - ISAKMP established - * - NAT-Traversal detected - * - NAT-KeepAlive needed (we are NATed) - */ - if (c->newest_isakmp_sa != st->st_serialno) - { - /* - * if newest is also valid, ignore this one, we will only use - * newest. - */ - struct state *st_newest; - - st_newest = state_with_serialno(c->newest_isakmp_sa); - if (st_newest - && (st_newest->st_state == STATE_MAIN_R3 || st_newest->st_state == STATE_MAIN_I4) - && (st_newest->nat_traversal & NAT_T_DETECTED) - && ((st_newest->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka)) - { - return; - } - } - set_cur_state(st); - nat_traversal_send_ka(st); - reset_cur_state(); - (*_kap_st)++; - } -} - -void nat_traversal_ka_event (void) -{ - unsigned int _kap_st = 0; - - _ka_evt = 0; /* ready to be reschedule */ - - for_each_state((void *)nat_traversal_ka_event_state, &_kap_st); - - /* if there are still states who needs Keep-Alive, schedule new event */ - if (_kap_st) - nat_traversal_new_ka_event(); -} - -struct _new_mapp_nfo { - ip_address addr; - u_int16_t sport, dport; -}; - -static void nat_traversal_find_new_mapp_state (struct state *st, void *data) -{ - connection_t *c = st->st_connection; - struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data; - - if (c != NULL - && sameaddr(&c->spd.that.host_addr, &(nfo->addr)) - && c->spd.that.host_port == nfo->sport) - { - - /* change host port */ - c->spd.that.host_port = nfo->dport; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state) - || IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (!update_ipsec_sa(st)) - { - /* - * If ipsec update failed, restore old port or we'll - * not be able to update anymore. - */ - c->spd.that.host_port = nfo->sport; - } - } - } -} - -static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport, - const ip_address *dst, u_int16_t dport) -{ - char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF]; - struct _new_mapp_nfo nfo; - - addrtot(src, 0, srca, ADDRTOT_BUF); - addrtot(dst, 0, dsta, ADDRTOT_BUF); - - if (!sameaddr(src, dst)) - { - loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: " - "address change currently not supported [%s:%d,%s:%d]", - srca, sport, dsta, dport); - return -1; - } - - if (sport == dport) - { - /* no change */ - return 0; - } - - DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport); - - nfo.addr = *src; - nfo.sport = sport; - nfo.dport = dport; - - for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo); - - return 0; -} - -void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st) -{ - connection_t *c = st ? st->st_connection : NULL; - struct iface *i = NULL; - - if ((st == NULL) || (c == NULL)) - return; - - if (md) - { - /* - * If source port has changed, update (including other states and - * established kernel SA) - */ - if (c->spd.that.host_port != md->sender_port) - { - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - &c->spd.that.host_addr, md->sender_port); - } - - /* - * If interface type has changed, update local port (500/4500) - */ - if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !md->iface->ike_float) - || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && md->iface->ike_float)) - { - c->spd.this.host_port = (md->iface->ike_float) - ? NAT_T_IKE_FLOAT_PORT : pluto_port; - - DBG(DBG_NATT, - DBG_log("NAT-T: updating local port to %d", c->spd.this.host_port); - ); - } - } - - /* - * If we're initiator and NAT-T (with port floating) is detected, we - * need to change port (MAIN_I3 or QUICK_I1) - */ - if ((st->st_state == STATE_MAIN_I3 || st->st_state == STATE_QUICK_I1) - && (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) - && (st->nat_traversal & NAT_T_DETECTED) - && (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT)) - { - DBG(DBG_NATT, - DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT); - ) - c->spd.this.host_port = NAT_T_IKE_FLOAT_PORT; - c->spd.that.host_port = NAT_T_IKE_FLOAT_PORT; - /* - * Also update pending connections or they will be deleted if uniqueids - * option is set. - */ - update_pending(st, st); - } - - /* - * Find valid interface according to local port (500/4500) - */ - if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !c->interface->ike_float) - || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && c->interface->ike_float)) - { - for (i = interfaces; i != NULL; i = i->next) - { - if (sameaddr(&c->interface->addr, &i->addr) - && i->ike_float != c->interface->ike_float) - { - DBG(DBG_NATT, - DBG_log("NAT-T: using interface %s:%d", i->rname, - i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port); - ) - c->interface = i; - break; - } - } - } -} - -struct _new_kernel_mapp_nfo { - u_int32_t reqid; - u_int32_t spi; - ip_address *addr; -}; - -static void nat_t_new_kernel_mapp (struct state *st, void *data) -{ - connection_t *c = st->st_connection; - struct _new_kernel_mapp_nfo *nfo = (struct _new_kernel_mapp_nfo *)data; - - if (c != NULL && st->st_esp.present - && nfo->spi == st->st_esp.our_spi - && nfo->reqid == c->spd.reqid) - { - u_int16_t port = ntohs(portof(nfo->addr)); - - DBG(DBG_NATT, { - char text_said[SATOT_BUF]; - char olda[ADDRTOT_BUF]; - char newa[ADDRTOT_BUF]; - ip_said said; - - initsaid(&c->spd.that.host_addr, nfo->spi, SA_ESP, &said); - satot(&said, 0, text_said, SATOT_BUF); - addrtot(&c->spd.that.host_addr, 0, olda, ADDRTOT_BUF); - addrtot(nfo->addr, 0, newa, ADDRTOT_BUF); - - DBG_log("new kernel mapping %s %s:%d %s:%d", - text_said, olda, c->spd.that.host_port, newa, port); - }) - - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - nfo->addr, port); - } -} - -void process_nat_t_new_mapping(u_int32_t reqid, u_int32_t spi, - ip_address *new_end) -{ - struct _new_kernel_mapp_nfo nfo = { - .reqid = reqid, - .spi = spi, - .addr = new_end, - }; - for_each_state((void *)nat_t_new_kernel_mapp, &nfo); -} - diff --git a/src/pluto/nat_traversal.h b/src/pluto/nat_traversal.h deleted file mode 100644 index 80bdaf787..000000000 --- a/src/pluto/nat_traversal.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2002-2003 Mathieu Lafon - * Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _NAT_TRAVERSAL_H -#define _NAT_TRAVERSAL_H - -#include "packet.h" - -#define NAT_TRAVERSAL_IETF_00_01 1 -#define NAT_TRAVERSAL_IETF_02_03 2 -#define NAT_TRAVERSAL_RFC 3 - -#define NAT_TRAVERSAL_NAT_BHND_ME 30 -#define NAT_TRAVERSAL_NAT_BHND_PEER 31 - -#define NAT_TRAVERSAL_METHOD (0xffffffff - LELEM(30) - LELEM(31)) - -/** - * NAT-Traversal methods which need NAT-D - */ -#define NAT_T_WITH_NATD \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which need NAT-OA - */ -#define NAT_T_WITH_NATOA \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which use NAT-KeepAlive - */ -#define NAT_T_WITH_KA \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which use floating port - */ -#define NAT_T_WITH_PORT_FLOATING \ - ( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_RFC) ) - -/** - * NAT-Traversal methods which use officials values (RFC) - */ -#define NAT_T_WITH_RFC_VALUES \ - ( LELEM(NAT_TRAVERSAL_RFC) ) - -/** - * NAT-Traversal detected - */ -#define NAT_T_DETECTED \ - ( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) ) - -/** - * NAT-T Port Floating - */ -#define NAT_T_IKE_FLOAT_PORT 4500 - -void init_nat_traversal (bool activate, unsigned int keep_alive_period, - bool fka, bool spf); - -extern bool nat_traversal_enabled; -extern bool nat_traversal_support_non_ike; -extern bool nat_traversal_support_port_floating; - -/** - * NAT-D - */ -void nat_traversal_natd_lookup(struct msg_digest *md); -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, - struct msg_digest *md); -#endif - -/** - * NAT-OA - */ -void nat_traversal_natoa_lookup(struct msg_digest *md); -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs, - struct state *st); -#endif - -/** - * NAT-keep_alive - */ -void nat_traversal_new_ka_event (void); -void nat_traversal_ka_event (void); - -void nat_traversal_show_result (u_int32_t nt, u_int16_t sport); - -int nat_traversal_espinudp_socket (int sk, u_int32_t type); - -/** - * Vendor ID - */ -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs); -#endif -u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid); - -void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st); - -/** - * New NAT mapping - */ -void process_nat_t_new_mapping(u_int32_t reqid, u_int32_t spi, - ip_address *new_end); - -/** - * IKE port floating - */ -bool -nat_traversal_port_float(struct state *st, struct msg_digest *md, bool in); - -/** - * Encapsulation mode macro (see demux.c) - */ -#define NAT_T_ENCAPSULATION_MODE(st,nat_t_policy) ( \ - ((st)->nat_traversal & NAT_T_DETECTED) \ - ? ( ((nat_t_policy) & POLICY_TUNNEL) \ - ? ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \ - ? (ENCAPSULATION_MODE_UDP_TUNNEL_RFC) \ - : (ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS) \ - ) \ - : ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \ - ? (ENCAPSULATION_MODE_UDP_TRANSPORT_RFC) \ - : (ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS) \ - ) \ - ) \ - : ( ((st)->st_policy & POLICY_TUNNEL) \ - ? (ENCAPSULATION_MODE_TUNNEL) \ - : (ENCAPSULATION_MODE_TRANSPORT) \ - ) \ - ) - -#endif /* _NAT_TRAVERSAL_H */ - diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c deleted file mode 100644 index c299e3d39..000000000 --- a/src/pluto/ocsp.c +++ /dev/null @@ -1,1558 +0,0 @@ -/* Support of the Online Certificate Status Protocol (OCSP) - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "smartcard.h" -#include "whack.h" -#include "keys.h" -#include "fetch.h" -#include "ocsp.h" - -#define NONCE_LENGTH 16 - -static const char *const cert_status_names[] = { - "good", - "revoked", - "unknown", - "undefined" -}; - - -static const char *const response_status_names[] = { - "successful", - "malformed request", - "internal error", - "try later", - "status #4", - "signature required", - "unauthorized" -}; - -/* response container */ -typedef struct response response_t; - -struct response { - chunk_t tbs; - identification_t *responder_id_name; - chunk_t responder_id_key; - time_t produced_at; - chunk_t responses; - chunk_t nonce; - int algorithm; - chunk_t signature; -}; - -const response_t empty_response = { - { NULL, 0 } , /* tbs */ - NULL , /* responder_id_name */ - { NULL, 0 } , /* responder_id_key */ - UNDEFINED_TIME, /* produced_at */ - { NULL, 0 } , /* single_response */ - { NULL, 0 } , /* nonce */ - OID_UNKNOWN , /* signature_algorithm */ - { NULL, 0 } /* signature */ -}; - -/* single response container */ -typedef struct single_response single_response_t; - -struct single_response { - single_response_t *next; - int hash_algorithm; - chunk_t issuer_name_hash; - chunk_t issuer_key_hash; - chunk_t serialNumber; - cert_status_t status; - time_t revocationTime; - crl_reason_t revocationReason; - time_t thisUpdate; - time_t nextUpdate; -}; - -const single_response_t empty_single_response = { - NULL , /* *next */ - OID_UNKNOWN , /* hash_algorithm */ - { NULL, 0 } , /* issuer_name_hash */ - { NULL, 0 } , /* issuer_key_hash */ - { NULL, 0 } , /* serial_number */ - CERT_UNDEFINED , /* status */ - UNDEFINED_TIME , /* revocationTime */ - CRL_REASON_UNSPECIFIED, /* revocationReason */ - UNDEFINED_TIME , /* this_update */ - UNDEFINED_TIME /* next_update */ -}; - - -/* list of single requests */ -typedef struct request_list request_list_t; -struct request_list { - chunk_t request; - request_list_t *next; -}; - -/* some OCSP specific prefabricated ASN.1 constants */ -static const chunk_t ASN1_nonce_oid = chunk_from_chars( - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 -); -static const chunk_t ASN1_response_oid = chunk_from_chars( - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 -); -static const chunk_t ASN1_response_content = chunk_from_chars( - 0x04, 0x0D, - 0x30, 0x0B, - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 -); - -/* default OCSP uri */ -static chunk_t ocsp_default_uri; - -/* ocsp cache: pointer to first element */ -static ocsp_location_t *ocsp_cache = NULL; - -/* static temporary storage for ocsp requestor information */ -static cert_t *ocsp_requestor_cert = NULL; - -static smartcard_t *ocsp_requestor_sc = NULL; - -static private_key_t *ocsp_requestor_key = NULL; - -/** - * ASN.1 definition of ocspResponse - */ -static const asn1Object_t ocspResponseObjects[] = { - { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */ - { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */ - { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ - { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */ - { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define OCSP_RESPONSE_STATUS 1 -#define OCSP_RESPONSE_TYPE 4 -#define OCSP_RESPONSE 5 - -/** - * ASN.1 definition of basicResponse - */ -static const asn1Object_t basicResponseObjects[] = { - { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE | - ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */ - { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */ - { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */ - { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ - { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ - { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 16 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */ - { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */ - { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */ - { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */ - { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define BASIC_RESPONSE_TBS_DATA 1 -#define BASIC_RESPONSE_VERSION 3 -#define BASIC_RESPONSE_ID_BY_NAME 5 -#define BASIC_RESPONSE_ID_BY_KEY 8 -#define BASIC_RESPONSE_PRODUCED_AT 10 -#define BASIC_RESPONSE_RESPONSES 11 -#define BASIC_RESPONSE_EXT_ID 15 -#define BASIC_RESPONSE_CRITICAL 16 -#define BASIC_RESPONSE_EXT_VALUE 17 -#define BASIC_RESPONSE_ALGORITHM 20 -#define BASIC_RESPONSE_SIGNATURE 21 -#define BASIC_RESPONSE_CERTIFICATE 24 - -/** - * ASN.1 definition of responses - */ -static const asn1Object_t responsesObjects[] = { - { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define RESPONSES_SINGLE_RESPONSE 1 - -/** - * ASN.1 definition of singleResponse - */ -static const asn1Object_t singleResponseObjects[] = { - { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ - { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ - { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ - { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */ - { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */ - { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */ - { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */ - { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ - { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ - { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */ - { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */ - { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */ - { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */ - { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ - { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */ - { 4, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 24 */ - { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define SINGLE_RESPONSE_ALGORITHM 2 -#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3 -#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4 -#define SINGLE_RESPONSE_SERIAL_NUMBER 5 -#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6 -#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8 -#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9 -#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11 -#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14 -#define SINGLE_RESPONSE_THIS_UPDATE 16 -#define SINGLE_RESPONSE_NEXT_UPDATE 18 -#define SINGLE_RESPONSE_EXT_ID 23 -#define SINGLE_RESPONSE_CRITICAL 24 -#define SINGLE_RESPONSE_EXT_VALUE 25 - -/* - * Build an ocsp location from certificate information - * without unsharing its contents - */ -static bool build_ocsp_location(const cert_t *cert, ocsp_location_t *location) -{ - certificate_t *certificate = cert->cert; - identification_t *issuer = certificate->get_issuer(certificate); - x509_t *x509 = (x509_t*)certificate; - chunk_t issuer_dn = issuer->get_encoding(issuer); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - hasher_t *hasher; - static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */ - - enumerator_t *enumerator = x509->create_ocsp_uri_enumerator(x509); - - location->uri = NULL; - while (enumerator->enumerate(enumerator, &location->uri)) - { - break; - } - enumerator->destroy(enumerator); - - if (location->uri == NULL) - { - ca_info_t *ca = get_ca_info(issuer, authKeyID); - if (ca && ca->ocspuri) - { - location->uri = ca->ocspuri; - } - else - { /* abort if no ocsp location uri is defined */ - return FALSE; - } - } - - /* compute authNameID from as SHA-1 hash of issuer DN */ - location->authNameID = chunk_create(digest, HASH_SIZE_SHA1); - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - return FALSE; - } - hasher->get_hash(hasher, issuer_dn, digest); - hasher->destroy(hasher); - - location->next = NULL; - location->issuer = issuer; - location->authKeyID = authKeyID; - - if (authKeyID.ptr == NULL) - { - cert_t *authcert = get_authcert(issuer, authKeyID, X509_CA); - - if (authcert) - { - x509_t *x509 = (x509_t*)authcert->cert; - - location->authKeyID = x509->get_subjectKeyIdentifier(x509); - } - } - - location->nonce = chunk_empty; - location->certinfo = NULL; - - return TRUE; -} - -/** - * Compare two ocsp locations for equality - */ -static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b) -{ - return ((a->authKeyID.ptr) - ? same_keyid(a->authKeyID, b->authKeyID) - : a->issuer->equals(a->issuer, b->issuer)) - && streq(a->uri, b->uri); -} - -/** - * Find an existing ocsp location in a chained list - */ -ocsp_location_t* get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain) -{ - - while (chain) - { - if (same_ocsp_location(loc, chain)) - return chain; - chain = chain->next; - } - return NULL; -} - -/** - * Retrieves the status of a cert from the ocsp cache - * returns CERT_UNDEFINED if no status is found - */ -static cert_status_t get_ocsp_status(const ocsp_location_t *loc, - chunk_t serialNumber, - time_t *nextUpdate, time_t *revocationTime, - crl_reason_t *revocationReason) -{ - ocsp_certinfo_t *certinfo, **certinfop; - int cmp = -1; - - /* find location */ - ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache); - - if (location == NULL) - return CERT_UNDEFINED; - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp == 0) - { - *nextUpdate = certinfo->nextUpdate; - *revocationTime = certinfo->revocationTime; - *revocationReason = certinfo->revocationReason; - return certinfo->status; - } - - return CERT_UNDEFINED; -} - -/** - * Verify the ocsp status of a certificate - */ -cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until, - time_t *revocationDate, - crl_reason_t *revocationReason) -{ - x509_t *x509 = (x509_t*)cert->cert; - chunk_t serialNumber = x509->get_serial(x509); - cert_status_t status; - ocsp_location_t location; - time_t nextUpdate = UNDEFINED_TIME; - - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - - /* is an ocsp location defined? */ - if (!build_ocsp_location(cert, &location)) - { - return CERT_UNDEFINED; - } - - lock_ocsp_cache("verify_by_ocsp"); - status = get_ocsp_status(&location, serialNumber, &nextUpdate - , revocationDate, revocationReason); - unlock_ocsp_cache("verify_by_ocsp"); - - if (status == CERT_UNDEFINED || nextUpdate < time(NULL)) - { - plog("ocsp status is stale or not in cache"); - add_ocsp_fetch_request(&location, serialNumber); - - /* inititate fetching of ocsp status */ - wake_fetch_thread("verify_by_ocsp"); - } - *until = nextUpdate; - return status; -} - -/** - * Check if an ocsp status is about to expire - */ -void check_ocsp(void) -{ - ocsp_location_t *location; - - lock_ocsp_cache("check_ocsp"); - location = ocsp_cache; - - while (location) - { - char buf[BUF_LEN]; - bool first = TRUE; - ocsp_certinfo_t *certinfo = location->certinfo; - - while (certinfo) - { - if (!certinfo->once) - { - time_t time_left = certinfo->nextUpdate - time(NULL); - - DBG(DBG_CONTROL, - if (first) - { - DBG_log("issuer: \"%Y\"", location->issuer); - if (location->authKeyID.ptr) - { - datatot(location->authKeyID.ptr, location->authKeyID.len - , ':', buf, BUF_LEN); - DBG_log("authkey: %s", buf); - } - first = FALSE; - } - datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len - , ':', buf, BUF_LEN); - DBG_log("serial: %s, %ld seconds left", buf, time_left) - ) - - if (time_left < 2*crl_check_interval) - add_ocsp_fetch_request(location, certinfo->serialNumber); - } - certinfo = certinfo->next; - } - location = location->next; - } - unlock_ocsp_cache("check_ocsp"); -} - -/** - * frees the allocated memory of a certinfo struct - */ -static void free_certinfo(ocsp_certinfo_t *certinfo) -{ - free(certinfo->serialNumber.ptr); - free(certinfo); -} - -/** - * frees all certinfos in a chained list - */ -static void free_certinfos(ocsp_certinfo_t *chain) -{ - ocsp_certinfo_t *certinfo; - - while (chain) - { - certinfo = chain; - chain = chain->next; - free_certinfo(certinfo); - } -} - -/** - * Frees the memory allocated to an ocsp location including all certinfos - */ -static void free_ocsp_location(ocsp_location_t* location) -{ - DESTROY_IF(location->issuer); - free(location->authNameID.ptr); - free(location->authKeyID.ptr); - free(location->uri); - free_certinfos(location->certinfo); - free(location); -} - -/* - * Free a chained list of ocsp locations - */ -void free_ocsp_locations(ocsp_location_t **chain) -{ - while (*chain) - { - ocsp_location_t *location = *chain; - *chain = location->next; - free_ocsp_location(location); - } -} - -/** - * Free the ocsp cache - */ -void free_ocsp_cache(void) -{ - lock_ocsp_cache("free_ocsp_cache"); - free_ocsp_locations(&ocsp_cache); - unlock_ocsp_cache("free_ocsp_cache"); -} - -/** - * Frees the ocsp cache and global variables - */ -void free_ocsp(void) -{ - free(ocsp_default_uri.ptr); - free_ocsp_cache(); -} - -/** - * List a chained list of ocsp_locations - */ -void list_ocsp_locations(ocsp_location_t *location, bool requests, - bool utc, bool strict) -{ - bool first = TRUE; - - while (location) - { - ocsp_certinfo_t *certinfo = location->certinfo; - - if (certinfo) - { - if (first) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of OCSP %s:", requests ? - "Fetch Requests" : "Responses"); - first = FALSE; - } - whack_log(RC_COMMENT, " "); - if (location->issuer) - { - whack_log(RC_COMMENT, " issuer: \"%Y\"", location->issuer); - } - whack_log(RC_COMMENT, " uri: '%s'", location->uri); - if (location->authNameID.ptr) - { - whack_log(RC_COMMENT, " authname: %#B", &location->authNameID); - } - if (location->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &location->authKeyID); - } - while (certinfo) - { - chunk_t serial = chunk_skip_zero(certinfo->serialNumber); - - if (requests) - { - whack_log(RC_COMMENT, " serial: %#B, %d trials", - &serial, certinfo->trials); - } - else if (certinfo->once) - { - whack_log(RC_COMMENT, " serial: %#B, %s, once%s", - &serial, cert_status_names[certinfo->status], - (certinfo->nextUpdate < time(NULL))? " (expired)": ""); - } - else - { - whack_log(RC_COMMENT, " serial: %#B, %s, until %T %s", - &serial, cert_status_names[certinfo->status], - &certinfo->nextUpdate, utc, - check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict)); - } - certinfo = certinfo->next; - } - } - location = location->next; - } -} - -/** - * List the ocsp cache - */ -void list_ocsp_cache(bool utc, bool strict) -{ - lock_ocsp_cache("list_ocsp_cache"); - list_ocsp_locations(ocsp_cache, FALSE, utc, strict); - unlock_ocsp_cache("list_ocsp_cache"); -} - -static bool get_ocsp_requestor_cert(ocsp_location_t *location) -{ - cert_t *cert = NULL; - - /* initialize temporary static storage */ - ocsp_requestor_cert = NULL; - ocsp_requestor_sc = NULL; - ocsp_requestor_key = NULL; - - for (;;) - { - certificate_t *certificate; - - /* looking for a certificate from the same issuer */ - cert = get_x509cert(location->issuer, location->authKeyID, cert); - if (cert == NULL) - { - break; - } - certificate = cert->cert; - DBG(DBG_CONTROL, - DBG_log("candidate: '%Y'", certificate->get_subject(certificate)); - ) - - if (cert->smartcard) - { - /* look for a matching private key on a smartcard */ - smartcard_t *sc = scx_get(cert); - - if (sc) - { - DBG(DBG_CONTROL, - DBG_log("matching smartcard found") - ) - if (sc->valid) - { - ocsp_requestor_cert = cert; - ocsp_requestor_sc = sc; - return TRUE; - } - plog("unable to sign ocsp request without PIN"); - } - } - else - { - /* look for a matching private key in the chained list */ - private_key_t *private = get_x509_private_key(cert); - - if (private) - { - DBG(DBG_CONTROL, - DBG_log("matching private key found") - ) - ocsp_requestor_cert = cert; - ocsp_requestor_key = private; - return TRUE; - } - } - } - return FALSE; -} - -static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) -{ - hasher_t *hasher; - u_char *pos; - chunk_t digest; - chunk_t digest_info, sigdata; - size_t siglen = 0; - - if (!scx_establish_context(sc) || !scx_login(sc)) - { - scx_release_context(sc); - return chunk_empty; - } - - siglen = scx_get_keylength(sc); - - if (siglen == 0) - { - plog("failed to get keylength from smartcard"); - scx_release_context(sc); - return chunk_empty; - } - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)" - , (int)sc->slot, sc->id) - ) - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - return chunk_empty; - } - hasher->allocate_hash(hasher, tbs, &digest); - hasher->destroy(hasher); - - /* according to PKCS#1 v2.1 digest must be packaged into - * an ASN.1 structure for encryption - */ - digest_info = asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_algorithmIdentifier(OID_SHA1) - , asn1_wrap(ASN1_OCTET_STRING, "m", digest)); - - pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); - *pos++ = 0x00; - scx_sign_hash(sc, digest_info.ptr, digest_info.len, pos, siglen); - free(digest_info.ptr); - - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - return sigdata; -} - -/** - * build signature into ocsp request gets built only if a request cert - * with a corresponding private key is found - */ -static chunk_t build_signature(chunk_t tbsRequest) -{ - chunk_t sigdata, cert, certs = chunk_empty; - - if (ocsp_requestor_sc) - { - /* RSA signature is done on smartcard */ - sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc); - } - else - { - /* RSA signature is done in software */ - sigdata = x509_build_signature(tbsRequest, OID_SHA1, ocsp_requestor_key, - TRUE); - } - if (sigdata.ptr == NULL) - { - return chunk_empty; - } - - /* include our certificate */ - if (ocsp_requestor_cert->cert->get_encoding(ocsp_requestor_cert->cert, - CERT_ASN1_DER, &cert)) - { - certs = asn1_wrap(ASN1_CONTEXT_C_0, "m", - asn1_wrap(ASN1_SEQUENCE, "m", cert)); - } - /* build signature comprising algorithm, signature and cert */ - return asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_wrap(ASN1_SEQUENCE, "mmm" - , asn1_algorithmIdentifier(OID_SHA1_WITH_RSA) - , sigdata - , certs - ) - ); -} - -/** - * Build request (into requestList) - * no singleRequestExtensions used - */ -static chunk_t build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo) -{ - chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "mmmm" - , asn1_algorithmIdentifier(OID_SHA1) - , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID) - , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID) - , asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber)); - - return asn1_wrap(ASN1_SEQUENCE, "m", reqCert); -} - -/** - * build requestList (into TBSRequest) - */ -static chunk_t build_request_list(ocsp_location_t *location) -{ - chunk_t requestList; - request_list_t *reqs = NULL; - ocsp_certinfo_t *certinfo = location->certinfo; - u_char *pos; - - size_t datalen = 0; - - /* build content */ - while (certinfo) - { - /* build request for every certificate in list - * and store them in a chained list - */ - request_list_t *req = malloc_thing(request_list_t); - - req->request = build_request(location, certinfo); - req->next = reqs; - reqs = req; - - datalen += req->request.len; - certinfo = certinfo->next; - } - - pos = asn1_build_object(&requestList, ASN1_SEQUENCE, datalen); - - /* copy all in chained list, free list afterwards */ - while (reqs) - { - request_list_t *req = reqs; - - mv_chunk(&pos, req->request); - reqs = reqs->next; - free(req); - } - - return requestList; -} - -/** - * Build requestorName (into TBSRequest) - */ -static chunk_t build_requestor_name(void) -{ - certificate_t *certificate = ocsp_requestor_cert->cert; - identification_t *subject = certificate->get_subject(certificate); - - return asn1_wrap(ASN1_CONTEXT_C_1, "m" - , asn1_simple_object(ASN1_CONTEXT_C_4 - , subject->get_encoding(subject))); -} - -/** - * build nonce extension (into requestExtensions) - */ -static chunk_t build_nonce_extension(ocsp_location_t *location) -{ - rng_t *rng; - - /* generate a random nonce */ - location->nonce.ptr = malloc(NONCE_LENGTH), - location->nonce.len = NONCE_LENGTH; - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - rng->get_bytes(rng, location->nonce.len, location->nonce.ptr); - rng->destroy(rng); - - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_nonce_oid - , asn1_simple_object(ASN1_OCTET_STRING, location->nonce)); -} - -/** - * Build requestExtensions (into TBSRequest) - */ -static chunk_t build_request_ext(ocsp_location_t *location) -{ - return asn1_wrap(ASN1_CONTEXT_C_2, "m" - , asn1_wrap(ASN1_SEQUENCE, "mm" - , build_nonce_extension(location) - , asn1_wrap(ASN1_SEQUENCE, "cc" - , ASN1_response_oid - , ASN1_response_content - ) - ) - ); -} - -/** - * Build TBSRequest (into OCSPRequest) - */ -static chunk_t build_tbs_request(ocsp_location_t *location, bool has_requestor_cert) -{ - /* version is skipped since the default is ok */ - return asn1_wrap(ASN1_SEQUENCE, "mmm" - , (has_requestor_cert) - ? build_requestor_name() - : chunk_empty - , build_request_list(location) - , build_request_ext(location)); -} - -/** - * Assembles an ocsp request to given location - * and sets nonce field in location to the sent nonce - */ -chunk_t build_ocsp_request(ocsp_location_t *location) -{ - bool has_requestor_cert; - chunk_t tbsRequest, signature; - - DBG(DBG_CONTROL, - DBG_log("assembling ocsp request"); - DBG_log("issuer: \"%Y\"", location->issuer); - if (location->authKeyID.ptr) - { - DBG_log("authkey: %#B", &location->authKeyID); - } - ) - lock_certs_and_keys("build_ocsp_request"); - - /* looks for requestor cert and matching private key */ - has_requestor_cert = get_ocsp_requestor_cert(location); - - /* build content */ - tbsRequest = build_tbs_request(location, has_requestor_cert); - - /* sign tbsReuqest */ - signature = (has_requestor_cert)? build_signature(tbsRequest) - : chunk_empty; - - unlock_certs_and_keys("build_ocsp_request"); - - return asn1_wrap(ASN1_SEQUENCE, "mm" - , tbsRequest - , signature); -} - -/** - * Check if the OCSP response has a valid signature - */ -static bool valid_ocsp_response(response_t *res) -{ - int pathlen, pathlen_constraint; - cert_t *authcert; - - lock_authcert_list("valid_ocsp_response"); - - authcert = get_authcert(res->responder_id_name, res->responder_id_key, - X509_OCSP_SIGNER | X509_CA); - if (authcert == NULL) - { - plog("no matching ocsp signer cert found"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("ocsp signer cert found") - ) - - if (!x509_check_signature(res->tbs, res->signature, res->algorithm, - authcert->cert)) - { - plog("signature of ocsp response is invalid"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("signature of ocsp response is valid") - ) - - - for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++) - { - cert_t *cert = authcert; - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - time_t not_before, not_after; - - DBG(DBG_CONTROL, - DBG_log("subject: '%Y'", subject); - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr) - { - DBG_log("authkey: %#B", &authKeyID); - } - ) - - if (!certificate->get_validity(certificate, NULL, ¬_before, ¬_after)) - { - plog("certificate is invalid (valid from %T to %T)", - ¬_before, FALSE, ¬_after, FALSE); - - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - - authcert = get_authcert(issuer, authKeyID, X509_CA); - if (authcert == NULL) - { - plog("issuer cacert not found"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("issuer cacert found") - ) - - if (!certificate->issued_by(certificate, authcert->cert)) - { - plog("certificate signature is invalid"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") - ) - - /* check path length constraint */ - pathlen_constraint = x509->get_constraint(x509, X509_PATH_LEN); - if (pathlen_constraint != X509_NO_CONSTRAINT && - pathlen > pathlen_constraint) - { - plog("path length of %d violates constraint of %d", - pathlen, pathlen_constraint); - return FALSE; - } - - /* check if cert is self-signed */ - if (x509->get_flags(x509) & X509_SELF_SIGNED) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca with a path length of %d", - pathlen) - ) - unlock_authcert_list("valid_ocsp_response"); - return TRUE; - } - } - plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; -} - -/** - * Parse a basic OCSP response - */ -static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) -{ - asn1_parser_t *parser; - chunk_t object; - u_int version; - int objectID; - int extn_oid = OID_UNKNOWN; - bool success = FALSE; - bool critical; - - parser = asn1_parser_create(basicResponseObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case BASIC_RESPONSE_TBS_DATA: - res->tbs = object; - break; - case BASIC_RESPONSE_VERSION: - version = (object.len)? (1 + (u_int)*object.ptr) : 1; - if (version != OCSP_BASIC_RESPONSE_VERSION) - { - plog("wrong ocsp basic response version (version= %i)", version); - goto end; - } - break; - case BASIC_RESPONSE_ID_BY_NAME: - res->responder_id_name = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG(DBG_PARSING, - DBG_log(" '%Y'", res->responder_id_name) - ) - break; - case BASIC_RESPONSE_ID_BY_KEY: - res->responder_id_key = object; - break; - case BASIC_RESPONSE_PRODUCED_AT: - res->produced_at = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case BASIC_RESPONSE_RESPONSES: - res->responses = object; - break; - case BASIC_RESPONSE_EXT_ID: - extn_oid = asn1_known_oid(object); - break; - case BASIC_RESPONSE_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case BASIC_RESPONSE_EXT_VALUE: - if (extn_oid == OID_NONCE) - res->nonce = object; - break; - case BASIC_RESPONSE_ALGORITHM: - res->algorithm = asn1_parse_algorithmIdentifier(object, - parser->get_level(parser)+1, NULL); - break; - case BASIC_RESPONSE_SIGNATURE: - res->signature = object; - break; - case BASIC_RESPONSE_CERTIFICATE: - { - cert_t *cert = malloc_thing(cert_t); - x509_t *x509; - - *cert = cert_empty; - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, object, - BUILD_END); - if (cert->cert == NULL) - { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("parsing of embedded ocsp certificate failed") - ) - cert_free(cert); - break; - } - x509 = (x509_t*)cert->cert; - - if ((x509->get_flags(x509) & X509_OCSP_SIGNER) && - trust_authcert_candidate(cert, NULL)) - { - add_authcert(cert, X509_OCSP_SIGNER); - } - else - { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("embedded ocsp certificate rejected") - ) - cert_free(cert); - } - } - break; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - return success; - -} - - -/** - * Parse an ocsp response and return the result as a response_t struct - */ -static response_status parse_ocsp_response(chunk_t blob, response_t * res) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - int ocspResponseType = OID_UNKNOWN; - bool success = FALSE; - response_status rStatus = STATUS_INTERNALERROR; - - parser = asn1_parser_create(ocspResponseObjects, blob); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) { - case OCSP_RESPONSE_STATUS: - rStatus = (response_status) *object.ptr; - - switch (rStatus) - { - case STATUS_SUCCESSFUL: - break; - case STATUS_MALFORMEDREQUEST: - case STATUS_INTERNALERROR: - case STATUS_TRYLATER: - case STATUS_SIGREQUIRED: - case STATUS_UNAUTHORIZED: - plog("ocsp response: server said '%s'" - , response_status_names[rStatus]); - goto end; - default: - goto end; - } - break; - case OCSP_RESPONSE_TYPE: - ocspResponseType = asn1_known_oid(object); - break; - case OCSP_RESPONSE: - { - switch (ocspResponseType) { - case OID_BASIC: - success = parse_basic_ocsp_response(object, - parser->get_level(parser)+1, res); - break; - default: - DBG(DBG_CONTROL, - DBG_log("ocsp response is not of type BASIC"); - DBG_dump_chunk("ocsp response OID: ", object); - ) - goto end; - } - } - break; - } - } - success &= parser->success(parser); - -end: - parser->destroy(parser); - return rStatus; -} - -/** - * Parse a basic OCSP response - */ -static bool parse_ocsp_single_response(chunk_t blob, int level0, - single_response_t *sres) -{ - asn1_parser_t *parser; - chunk_t object; - u_int extn_oid; - int objectID; - bool critical; - bool success = FALSE; - - parser = asn1_parser_create(singleResponseObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case SINGLE_RESPONSE_ALGORITHM: - sres->hash_algorithm = asn1_parse_algorithmIdentifier(object, - parser->get_level(parser)+1, NULL); - break; - case SINGLE_RESPONSE_ISSUER_NAME_HASH: - sres->issuer_name_hash = object; - break; - case SINGLE_RESPONSE_ISSUER_KEY_HASH: - sres->issuer_key_hash = object; - break; - case SINGLE_RESPONSE_SERIAL_NUMBER: - sres->serialNumber = object; - break; - case SINGLE_RESPONSE_CERT_STATUS_GOOD: - sres->status = CERT_GOOD; - break; - case SINGLE_RESPONSE_CERT_STATUS_REVOKED: - sres->status = CERT_REVOKED; - break; - case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME: - sres->revocationTime = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: - sres->revocationReason = (object.len == 1) - ? *object.ptr : CRL_REASON_UNSPECIFIED; - break; - case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: - sres->status = CERT_UNKNOWN; - break; - case SINGLE_RESPONSE_THIS_UPDATE: - sres->thisUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_NEXT_UPDATE: - sres->nextUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_EXT_ID: - extn_oid = asn1_known_oid(object); - break; - case SINGLE_RESPONSE_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - case SINGLE_RESPONSE_EXT_VALUE: - break; - } - } - success = parser->success(parser); - parser->destroy(parser); - return success; -} - -/** - * Add an ocsp location to a chained list - */ -ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc, - ocsp_location_t **chain) -{ - ocsp_location_t *location = malloc_thing(ocsp_location_t); - - /* unshare location fields */ - location->issuer = loc->issuer->clone(loc->issuer); - location->authNameID = chunk_clone(loc->authNameID); - location->authKeyID = chunk_clone(loc->authKeyID); - location->uri = strdup(loc->uri); - location->certinfo = NULL; - - /* insert new ocsp location in front of chain */ - location->next = *chain; - *chain = location; - - DBG(DBG_CONTROL, - DBG_log("new ocsp location added") - ) - - return location; -} - -/** - * add a certinfo struct to a chained list - */ -void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, - ocsp_location_t **chain, bool request) -{ - ocsp_location_t *location; - ocsp_certinfo_t *certinfo, **certinfop; - char buf[BUF_LEN]; - time_t now; - int cmp = -1; - - location = get_ocsp_location(loc, *chain); - if (location == NULL) - { - location = add_ocsp_location(loc, chain); - } - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(info->serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp != 0) - { - /* add a new certinfo entry */ - ocsp_certinfo_t *cnew = malloc_thing(ocsp_certinfo_t); - - cnew->serialNumber = chunk_clone(info->serialNumber); - cnew->next = certinfo; - cnew->trials = 0; - *certinfop = cnew; - certinfo = cnew; - } - - DBG(DBG_CONTROL, - datatot(info->serialNumber.ptr, info->serialNumber.len, ':' - , buf, BUF_LEN); - DBG_log("ocsp %s for serial %s %s" - , request?"fetch request":"certinfo" - , buf - , (cmp == 0)? (request?"already exists":"updated"):"added") - ) - - time(&now); - - if (request) - { - certinfo->status = CERT_UNDEFINED; - - if (cmp != 0) - { - certinfo->thisUpdate = now; - } - certinfo->nextUpdate = UNDEFINED_TIME; - } - else - { - certinfo->status = info->status; - certinfo->revocationTime = info->revocationTime; - certinfo->revocationReason = info->revocationReason; - - certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)? - info->thisUpdate : now; - - certinfo->once = (info->nextUpdate == UNDEFINED_TIME); - - certinfo->nextUpdate = (certinfo->once)? - (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate; - } -} - -/** - * Process received ocsp single response and add it to ocsp cache - */ -static void process_single_response(ocsp_location_t *location, - single_response_t *sres) -{ - ocsp_certinfo_t *certinfo, **certinfop; - int cmp = -1; - - if (sres->hash_algorithm != OID_SHA1) - { - plog("only SHA-1 hash supported in OCSP single response"); - return; - } - if (!(chunk_equals(sres->issuer_name_hash, location->authNameID) - && chunk_equals(sres->issuer_key_hash, location->authKeyID))) - { - plog("ocsp single response has wrong issuer"); - return; - } - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(sres->serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp != 0) - { - plog("received unrequested cert status from ocsp server"); - return; - } - - /* unlink cert from ocsp fetch request list */ - *certinfop = certinfo->next; - - /* update certinfo using the single response information */ - certinfo->thisUpdate = sres->thisUpdate; - certinfo->nextUpdate = sres->nextUpdate; - certinfo->status = sres->status; - certinfo->revocationTime = sres->revocationTime; - certinfo->revocationReason = sres->revocationReason; - - /* add or update certinfo in ocsp cache */ - lock_ocsp_cache("process_single_response"); - add_certinfo(location, certinfo, &ocsp_cache, FALSE); - unlock_ocsp_cache("process_single_response"); - - /* free certinfo unlinked from ocsp fetch request list */ - free_certinfo(certinfo); -} - -/** - * Destroy a response_t object - */ -static void free_response(response_t *res) -{ - DESTROY_IF(res->responder_id_name); -} - -/** - * Parse and verify ocsp response and update the ocsp cache - */ -void parse_ocsp(ocsp_location_t *location, chunk_t blob) -{ - response_t res = empty_response; - - /* parse the ocsp response without looking at the single responses yet */ - response_status status = parse_ocsp_response(blob, &res); - - if (status != STATUS_SUCCESSFUL) - { - plog("error in ocsp response"); - goto free; - } - /* check if there was a nonce in the request */ - if (location->nonce.ptr && res.nonce.ptr == NULL) - { - plog("ocsp response contains no nonce, replay attack possible"); - } - /* check if the nonce is identical */ - if (res.nonce.ptr && !chunk_equals(res.nonce, location->nonce)) - { - plog("invalid nonce in ocsp response"); - goto free; - } - /* check if the response is signed by a trusted key */ - if (!valid_ocsp_response(&res)) - { - plog("invalid ocsp response"); - goto free; - } - DBG(DBG_CONTROL, - DBG_log("valid ocsp response") - ) - - /* now parse the single responses one at a time */ - { - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(responsesObjects, res.responses); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == RESPONSES_SINGLE_RESPONSE) - { - single_response_t sres = empty_single_response; - - if (!parse_ocsp_single_response(object, - parser->get_level(parser)+1, &sres)) - { - goto end; - } - process_single_response(location, &sres); - } - } -end: - parser->destroy(parser); - } - -free: - free_response(&res); -} diff --git a/src/pluto/ocsp.h b/src/pluto/ocsp.h deleted file mode 100644 index 977cca3c8..000000000 --- a/src/pluto/ocsp.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Support of the Online Certificate Status Protocol (OCSP) Support - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "constants.h" - -#include - -/* constants */ - -#define OCSP_BASIC_RESPONSE_VERSION 1 -#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */ -#define OCSP_WARNING_INTERVAL 2 /* days */ - -/* OCSP response status */ - -typedef enum { - STATUS_SUCCESSFUL = 0, - STATUS_MALFORMEDREQUEST = 1, - STATUS_INTERNALERROR = 2, - STATUS_TRYLATER = 3, - STATUS_SIGREQUIRED = 5, - STATUS_UNAUTHORIZED= 6 -} response_status; - -/* OCSP access structures */ - -typedef struct ocsp_certinfo ocsp_certinfo_t; - -struct ocsp_certinfo { - ocsp_certinfo_t *next; - int trials; - chunk_t serialNumber; - cert_status_t status; - bool once; - crl_reason_t revocationReason; - time_t revocationTime; - time_t thisUpdate; - time_t nextUpdate; -}; - -typedef struct ocsp_location ocsp_location_t; - -struct ocsp_location { - ocsp_location_t *next; - identification_t *issuer; - chunk_t authNameID; - chunk_t authKeyID; - chunk_t nonce; - char *uri; - ocsp_certinfo_t *certinfo; -}; - -extern ocsp_location_t* get_ocsp_location(const ocsp_location_t *loc - , ocsp_location_t *chain); -extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc - , ocsp_location_t **chain); -extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info - , ocsp_location_t **chain, bool request); -extern void check_ocsp(void); -extern cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until - , time_t *revocationTime, crl_reason_t *revocationReason); -extern bool ocsp_set_request_cert(char* path); -extern void ocsp_set_default_uri(char* uri); -extern void ocsp_cache_add_cert(const cert_t* cert); -extern chunk_t build_ocsp_request(ocsp_location_t* location); -extern void parse_ocsp(ocsp_location_t* location, chunk_t blob); -extern void list_ocsp_locations(ocsp_location_t *location, bool requests - , bool utc, bool strict); -extern void list_ocsp_cache(bool utc, bool strict); -extern void free_ocsp_locations(ocsp_location_t **chain); -extern void free_ocsp_cache(void); -extern void free_ocsp(void); -extern void ocsp_purge_cache(void); diff --git a/src/pluto/packet.c b/src/pluto/packet.c deleted file mode 100644 index 35fc4afcc..000000000 --- a/src/pluto/packet.c +++ /dev/null @@ -1,1242 +0,0 @@ -/* parsing packets: formats and tools - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "packet.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ - -/* ISAKMP Header: for all messages - * layout from RFC 2408 "ISAKMP" section 3.1 - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Initiator ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Responder ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Message ID ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -static field_desc isa_fields[] = { - { ft_raw, COOKIE_SIZE, "initiator cookie", NULL }, - { ft_raw, COOKIE_SIZE, "responder cookie", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_enum, 8/BITS_PER_BYTE, "ISAKMP version", &version_names }, - { ft_enum, 8/BITS_PER_BYTE, "exchange type", &exchange_names }, - { ft_set, 8/BITS_PER_BYTE, "flags", flag_bit_names }, - { ft_raw, 32/BITS_PER_BYTE, "message ID", NULL }, - { ft_len, 32/BITS_PER_BYTE, "length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_hdr_desc = { "ISAKMP Message", isa_fields, sizeof(struct isakmp_hdr) }; - -/* Generic portion of all ISAKMP payloads. - * layout from RFC 2408 "ISAKMP" section 3.2 - * This describes the first 32-bit chunk of all payloads. - * The previous next payload depends on the actual payload type. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -static field_desc isag_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_generic_desc = { "ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) }; - - -/* ISAKMP Data Attribute (generic representation within payloads) - * layout from RFC 2408 "ISAKMP" section 3.3 - * This is not a payload type. - * In TLV format, this is followed by a value field. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * !A! Attribute Type ! AF=0 Attribute Length ! - * !F! ! AF=1 Attribute Value ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . AF=0 Attribute Value . - * . AF=1 Not Transmitted . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -/* Oakley Attributes */ -static field_desc isaat_fields_oakley[] = { - { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &oakley_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_oakley_attribute_desc = { - "ISAKMP Oakley attribute", - isaat_fields_oakley, sizeof(struct isakmp_attribute) }; - -/* IPsec DOI Attributes */ -static field_desc isaat_fields_ipsec[] = { - { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &ipsec_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipsec_attribute_desc = { - "ISAKMP IPsec DOI attribute", - isaat_fields_ipsec, sizeof(struct isakmp_attribute) }; - -/* Mode Config Attributes */ -static field_desc isaat_fields_modecfg[] = { - { ft_af_loose_enum, 16/BITS_PER_BYTE, "ModeCfg attr type", &modecfg_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_modecfg_attribute_desc = { - "ISAKMP ModeCfg attribute", - isaat_fields_modecfg, sizeof(struct isakmp_attribute) }; - -/* ISAKMP Security Association Payload - * layout from RFC 2408 "ISAKMP" section 3.4 - * A variable length Situation follows. - * Previous next payload: ISAKMP_NEXT_SA - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Situation ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isasa_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_sa_desc = { "ISAKMP Security Association Payload", isasa_fields, sizeof(struct isakmp_sa) }; - -static field_desc ipsec_sit_field[] = { - { ft_set, 32/BITS_PER_BYTE, "IPsec DOI SIT", &sit_bit_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_t) }; - -/* ISAKMP Proposal Payload - * layout from RFC 2408 "ISAKMP" section 3.5 - * A variable length SPI follows. - * Previous next payload: ISAKMP_NEXT_P - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! SPI (variable) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isap_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "proposal number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "protocol ID", &protocol_names }, - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "number of transforms", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, sizeof(struct isakmp_proposal) }; - -/* ISAKMP Transform Payload - * layout from RFC 2408 "ISAKMP" section 3.6 - * Variable length SA Attributes follow. - * Previous next payload: ISAKMP_NEXT_T - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Transform # ! Transform-Id ! RESERVED2 ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ SA Attributes ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -/* PROTO_ISAKMP */ -static field_desc isat_fields_isakmp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &isakmp_transformid_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_isakmp_transform_desc = { - "ISAKMP Transform Payload (ISAKMP)", - isat_fields_isakmp, sizeof(struct isakmp_transform) }; - -/* PROTO_IPSEC_AH */ -static field_desc isat_fields_ah[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transform_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ah_transform_desc = { - "ISAKMP Transform Payload (AH)", - isat_fields_ah, sizeof(struct isakmp_transform) }; - -/* PROTO_IPSEC_ESP */ -static field_desc isat_fields_esp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transform_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_esp_transform_desc = { - "ISAKMP Transform Payload (ESP)", - isat_fields_esp, sizeof(struct isakmp_transform) }; - -/* PROTO_IPCOMP */ -static field_desc isat_fields_ipcomp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ipcomp_transformid_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipcomp_transform_desc = { - "ISAKMP Transform Payload (COMP)", - isat_fields_ipcomp, sizeof(struct isakmp_transform) }; - - -/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.7 - * Variable Key Exchange Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_KE - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Key Exchange Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Identification Payload - * layout from RFC 2408 "ISAKMP" section 3.8 - * See "struct identity" declared later. - * Variable length Identification Data follow. - * Previous next payload: ISAKMP_NEXT_ID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! DOI Specific ID Data ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Identification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isaid_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, /* ??? depends on DOI? */ - { ft_nat, 8/BITS_PER_BYTE, "DOI specific A", NULL }, /* ??? depends on DOI? */ - { ft_nat, 16/BITS_PER_BYTE, "DOI specific B", NULL }, /* ??? depends on DOI? */ - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isaid_fields, sizeof(struct isakmp_id) }; - -/* IPSEC Identification Payload Content - * layout from RFC 2407 "IPsec DOI" section 4.6.2 - * See struct isakmp_id declared earlier. - * Note: Hashing skips the ISAKMP generic payload header - * Variable length Identification Data follow. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! Protocol ID ! Port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Identification Data ~ - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isaiid_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, - { ft_nat, 8/BITS_PER_BYTE, "Protocol ID", NULL }, /* ??? UDP/TCP or 0? */ - { ft_nat, 16/BITS_PER_BYTE, "port", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload (IPsec DOI)", isaiid_fields, sizeof(struct isakmp_ipsec_id) }; - -/* ISAKMP Certificate Payload: oddball fixed field beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.9 - * Variable length Certificate Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_CERT. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert Encoding ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isacert_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "cert encoding", &cert_type_names }, - { ft_end, 0, NULL, NULL } -}; - -/* Note: the size field of isakmp_ipsec_certificate_desc cannot be - * sizeof(struct isakmp_cert) because that will rounded up for padding. - */ - struct_desc isakmp_ipsec_certificate_desc = { "ISAKMP Certificate Payload", isacert_fields, ISAKMP_CERT_SIZE }; - -/* ISAKMP Certificate Request Payload: oddball field beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.10 - * Variable length Certificate Types and Certificate Authorities follow. - * Previous next payload: ISAKMP_NEXT_CR. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert. Type ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Authority ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isacr_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "cert type", &cert_type_names }, - { ft_end, 0, NULL, NULL } -}; - -/* Note: the size field of isakmp_ipsec_cert_req_desc cannot be - * sizeof(struct isakmp_cr) because that will rounded up for padding. - */ -struct_desc isakmp_ipsec_cert_req_desc = { "ISAKMP Certificate RequestPayload", isacr_fields, ISAKMP_CR_SIZE }; - -/* ISAKMP Hash Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.11 - * Variable length Hash Data follow. - * Previous next payload: ISAKMP_NEXT_HASH. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Hash Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_hash_desc = { "ISAKMP Hash Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Signature Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.12 - * Variable length Signature Data follow. - * Previous next payload: ISAKMP_NEXT_SIG. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Signature Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_signature_desc = { "ISAKMP Signature Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.13 - * Variable length Nonce Data follow. - * Previous next payload: ISAKMP_NEXT_NONCE. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Nonce Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Notification Payload - * layout from RFC 2408 "ISAKMP" section 3.14 - * This is followed by a variable length SPI - * and then possibly by variable length Notification Data. - * Previous next payload: ISAKMP_NEXT_N - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-ID ! SPI Size ! Notify Message Type ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Notification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isan_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC, ESP, ... */ - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_enum, 16/BITS_PER_BYTE, "Notify Message Type", ¬ification_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fields, sizeof(struct isakmp_notification) }; - -/* ISAKMP Delete Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length SPI. - * Previous next payload: ISAKMP_NEXT_D - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-Id ! SPI Size ! # of SPIs ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index(es) (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isad_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC */ - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "number of SPIs", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_delete_desc = { "ISAKMP Delete Payload", isad_fields, sizeof(struct isakmp_delete) }; - -/* ISAKMP Vendor ID Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length VID. - * Previous next payload: ISAKMP_NEXT_VID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Vendor ID (VID) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* MODECFG */ -/* - * From draft-dukes-ike-mode-cfg -3.2. Attribute Payload - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Next Payload ! RESERVED ! Payload Length ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Type ! RESERVED ! Identifier ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! ! - ~ Attributes ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ -static field_desc isaattr_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "Attr Msg Type", &attr_msg_type_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Identifier", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_attr_desc = { "ISAKMP Mode Attribute", isaattr_fields, sizeof(struct isakmp_mode_attr) }; - -/* ISAKMP NAT-Traversal NAT-D - * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2 - * - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! HASH of the address and port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP NAT-Traversal NAT-OA - * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2 - * - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! RESERVED ! RESERVED ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! IPv4 (4 octets) or IPv6 address (16 octets) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isanat_oa_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, - { ft_mbz, 24/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) }; - -/* descriptor for each payload type - * - * There is a slight problem in that some payloads differ, depending - * on the mode. Since this is table only used for top-level payloads, - * Proposal and Transform payloads need not be handled. - * That leaves only Identification payloads as a problem. - * We make all these entries NULL - */ -struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = { - NULL, /* 0 ISAKMP_NEXT_NONE (No other payload following) */ - &isakmp_sa_desc, /* 1 ISAKMP_NEXT_SA (Security Association) */ - NULL, /* 2 ISAKMP_NEXT_P (Proposal) */ - NULL, /* 3 ISAKMP_NEXT_T (Transform) */ - &isakmp_keyex_desc, /* 4 ISAKMP_NEXT_KE (Key Exchange) */ - NULL, /* 5 ISAKMP_NEXT_ID (Identification) */ - &isakmp_ipsec_certificate_desc, /* 6 ISAKMP_NEXT_CERT (Certificate) */ - &isakmp_ipsec_cert_req_desc, /* 7 ISAKMP_NEXT_CR (Certificate Request) */ - &isakmp_hash_desc, /* 8 ISAKMP_NEXT_HASH (Hash) */ - &isakmp_signature_desc, /* 9 ISAKMP_NEXT_SIG (Signature) */ - &isakmp_nonce_desc, /* 10 ISAKMP_NEXT_NONCE (Nonce) */ - &isakmp_notification_desc, /* 11 ISAKMP_NEXT_N (Notification) */ - &isakmp_delete_desc, /* 12 ISAKMP_NEXT_D (Delete) */ - &isakmp_vendor_id_desc, /* 13 ISAKMP_NEXT_VID (Vendor ID) */ - &isakmp_attr_desc, /* 14 ISAKMP_NEXT_ATTR (Mode Config) */ - NULL, /* 15 */ - NULL, /* 16 */ - NULL, /* 17 */ - NULL, /* 18 */ - NULL, /* 19 */ - &isakmp_nat_d, /* 20=130 ISAKMP_NEXT_NATD (NAT-D) */ - &isakmp_nat_oa, /* 20=131 ISAKMP_NEXT_NATOA (NAT-OA) */ -}; - -void -init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name) -{ - pbs->container = NULL; - pbs->desc = NULL; - pbs->name = name; - pbs->start = pbs->cur = start; - pbs->roof = start + len; - pbs->lenfld = NULL; - pbs->lenfld_desc = NULL; -} - -#ifdef DEBUG - -/* print a host struct - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - */ -void -DBG_print_struct(const char *label, const void *struct_ptr -, struct_desc *sd, bool len_meaningful) -{ - bool immediate = FALSE; - const u_int8_t *inp = struct_ptr; - field_desc *fp; - - DBG_log("%s%s:", label, sd->name); - - for (fp = sd->fields; fp->field_type != ft_end; fp++) - { - int i = fp->size; - u_int32_t n = 0; - - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - inp += i; - break; - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - switch (i) - { - case 8/BITS_PER_BYTE: - n = *(const u_int8_t *)inp; - break; - case 16/BITS_PER_BYTE: - n = *(const u_int16_t *)inp; - break; - case 32/BITS_PER_BYTE: - n = *(const u_int32_t *)inp; - break; - default: - bad_case(i); - } - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - if (!immediate && !len_meaningful) - break; - /* FALL THROUGH */ - case ft_nat: /* natural number (may be 0) */ - DBG_log(" %s: %lu", fp->name, (unsigned long)n); - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n)); - break; - case ft_set: /* bits representing set */ - DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n)); - break; - default: - bad_case(fp->field_type); - } - inp += i; - break; - - case ft_raw: /* bytes to be left in network-order */ - { - char m[50]; /* arbitrary limit on name width in log */ - - snprintf(m, sizeof(m), " %s:", fp->name); - DBG_dump(m, inp, i); - inp += i; - } - break; - default: - bad_case(fp->field_type); - } - } -} - -static void -DBG_prefix_print_struct(const pb_stream *pbs -, const char *label, const void *struct_ptr -, struct_desc *sd, bool len_meaningful) -{ - /* print out a title, with a prefix of asterisks to show - * the nesting level. - */ - char space[40]; /* arbitrary limit on label+flock-of-* */ - size_t len = strlen(label); - - if (sizeof(space) <= len) - { - DBG_print_struct(label, struct_ptr, sd, len_meaningful); - } - else - { - const pb_stream *p = pbs; - char *pre = &space[sizeof(space) - (len + 1)]; - - strcpy(pre, label); - - /* put at least one * out */ - for (;;) - { - if (pre <= space) - break; - *--pre = '*'; - if (p == NULL) - break; - p = p->container; - } - DBG_print_struct(pre, struct_ptr, sd, len_meaningful); - } -} - -#endif - -/* "parse" a network struct into a host struct. - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - * - * If obj_pbs is supplied, a new pb_stream is created for the - * variable part of the structure (this depends on their - * being one length field in the structure). The cursor of this - * new PBS is set to after the parsed part of the struct. - * - * This routine returns TRUE iff it succeeds. - */ - -bool -in_struct(void *struct_ptr, struct_desc *sd -, pb_stream *ins, pb_stream *obj_pbs) -{ - err_t ugh = NULL; - u_int8_t *cur = ins->cur; - - if (ins->roof - cur < (ptrdiff_t)sd->size) - { - ugh = builddiag("not enough room in input packet for %s", sd->name); - } - else - { - u_int8_t *roof = cur + sd->size; /* may be changed by a length field */ - u_int8_t *outp = struct_ptr; - bool immediate = FALSE; - field_desc *fp; - - for (fp = sd->fields; ugh == NULL; fp++) - { - size_t i = fp->size; - - passert(ins->roof - cur >= (ptrdiff_t)i); - passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i)); - passert(outp - (cur - ins->cur) == struct_ptr); - -#if 0 - DBG(DBG_PARSING, DBG_log("%d %s" - , (int) (cur - ins->cur), fp->name == NULL? "" : fp->name)); -#endif - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - for (; i != 0; i--) - { - if (*cur++ != 0) - { - ugh = builddiag("byte %d of %s must be zero, but is not" - , (int) (cur - ins->cur), sd->name); - break; - } - *outp++ = '\0'; /* probably redundant */ - } - break; - - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - { - u_int32_t n = 0; - - for (; i != 0; i--) - n = (n << BITS_PER_BYTE) | *cur++; - - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - { - u_int32_t len = fp->field_type == ft_len? n - : immediate? sd->size : n + sd->size; - - if (len < sd->size) - { - ugh = builddiag("%s of %s is smaller than minimum" - , fp->name, sd->name); - } - else if (pbs_left(ins) < len) - { - ugh = builddiag("%s of %s is larger than can fit" - , fp->name, sd->name); - } - else - { - roof = ins->cur + len; - } - break; - } - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - if (enum_name(fp->desc, n) == NULL) - { - ugh = builddiag("%s of %s has an unknown value: %lu" - , fp->name, sd->name, (unsigned long)n); - } - /* FALL THROUGH */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - break; - case ft_set: /* bits representing set */ - if (!testset(fp->desc, n)) - { - ugh = builddiag("bitset %s of %s has unknown member(s): %s" - , fp->name, sd->name, bitnamesof(fp->desc, n)); - } - break; - default: - break; - } - i = fp->size; - switch (i) - { - case 8/BITS_PER_BYTE: - *(u_int8_t *)outp = n; - break; - case 16/BITS_PER_BYTE: - *(u_int16_t *)outp = n; - break; - case 32/BITS_PER_BYTE: - *(u_int32_t *)outp = n; - break; - default: - bad_case(i); - } - outp += i; - break; - } - - case ft_raw: /* bytes to be left in network-order */ - for (; i != 0; i--) - { - *outp++ = *cur++; - } - break; - - case ft_end: /* end of field list */ - passert(cur == ins->cur + sd->size); - if (obj_pbs != NULL) - { - init_pbs(obj_pbs, ins->cur, roof - ins->cur, sd->name); - obj_pbs->container = ins; - obj_pbs->desc = sd; - obj_pbs->cur = cur; - } - ins->cur = roof; - DBG(DBG_PARSING - , DBG_prefix_print_struct(ins, "parse ", struct_ptr, sd, TRUE)); - return TRUE; - - default: - bad_case(fp->field_type); - } - } - } - - /* some failure got us here: report it */ - loglog(RC_LOG_SERIOUS, ugh); - return FALSE; -} - -bool -in_raw(void *bytes, size_t len, pb_stream *ins, const char *name) -{ - if (pbs_left(ins) < len) - { - loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name); - return FALSE; - } - else - { - if (bytes == NULL) - { - DBG(DBG_PARSING - , DBG_log("skipping %u raw bytes of %s (%s)" - , (unsigned) len, ins->name, name); - DBG_dump(name, ins->cur, len)); - } - else - { - memcpy(bytes, ins->cur, len); - DBG(DBG_PARSING - , DBG_log("parsing %u raw bytes of %s into %s" - , (unsigned) len, ins->name, name); - DBG_dump(name, bytes, len)); - } - ins->cur += len; - return TRUE; - } -} - -/* "emit" a host struct into a network packet. - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - * - * If obj_pbs is non-NULL, its pbs describes a new output stream set up - * to contain the object. The cursor will be left at the variable part. - * This new stream must subsequently be finalized by close_output_pbs(). - * - * The value of any field of type ft_len is computed, not taken - * from the input struct. The length is actually filled in when - * the object's output stream is finalized. If obj_pbs is NULL, - * finalization is done by out_struct before it returns. - * - * This routine returns TRUE iff it succeeds. - */ - -bool -out_struct(const void *struct_ptr, struct_desc *sd -, pb_stream *outs, pb_stream *obj_pbs) -{ - err_t ugh = NULL; - const u_int8_t *inp = struct_ptr; - u_int8_t *cur = outs->cur; - - DBG(DBG_EMITTING - , DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL)); - - if (outs->roof - cur < (ptrdiff_t)sd->size) - { - ugh = builddiag("not enough room left in output packet to place %s" - , sd->name); - } - else - { - bool immediate = FALSE; - pb_stream obj; - field_desc *fp; - - obj.lenfld = NULL; /* until a length field is discovered */ - obj.lenfld_desc = NULL; - - for (fp = sd->fields; ugh == NULL; fp++) - { - size_t i = fp->size; - - passert(outs->roof - cur >= (ptrdiff_t)i); - passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i)); - passert(inp - (cur - outs->cur) == struct_ptr); - -#if 0 - DBG(DBG_EMITTING, DBG_log("%d %s" - , (int) (cur - outs->cur), fp->name == NULL? "" : fp->name); -#endif - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - inp += i; - for (; i != 0; i--) - *cur++ = '\0'; - break; - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - { - u_int32_t n = 0; - - switch (i) - { - case 8/BITS_PER_BYTE: - n = *(const u_int8_t *)inp; - break; - case 16/BITS_PER_BYTE: - n = *(const u_int16_t *)inp; - break; - case 32/BITS_PER_BYTE: - n = *(const u_int32_t *)inp; - break; - default: - bad_case(i); - } - - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - if (immediate) - break; /* not a length */ - /* We can't check the length because it will likely - * be filled in after variable part is supplied. - * We do record where this is so that it can be - * filled in by a subsequent close_output_pbs(). - */ - passert(obj.lenfld == NULL); /* only one ft_len allowed */ - obj.lenfld = cur; - obj.lenfld_desc = fp; - break; - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - if (enum_name(fp->desc, n) == NULL) - { - ugh = builddiag("%s of %s has an unknown value: %lu" - , fp->name, sd->name, (unsigned long)n); - } - /* FALL THROUGH */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - break; - case ft_set: /* bits representing set */ - if (!testset(fp->desc, n)) - { - ugh = builddiag("bitset %s of %s has unknown member(s): %s" - , fp->name, sd->name, bitnamesof(fp->desc, n)); - } - break; - default: - break; - } - - while (i-- != 0) - { - cur[i] = (u_int8_t)n; - n >>= BITS_PER_BYTE; - } - inp += fp->size; - cur += fp->size; - break; - } - case ft_raw: /* bytes to be left in network-order */ - for (; i != 0; i--) - *cur++ = *inp++; - break; - case ft_end: /* end of field list */ - passert(cur == outs->cur + sd->size); - - obj.container = outs; - obj.desc = sd; - obj.name = sd->name; - obj.start = outs->cur; - obj.cur = cur; - obj.roof = outs->roof; /* limit of possible */ - /* obj.lenfld and obj.lenfld_desc already set */ - - if (obj_pbs == NULL) - { - close_output_pbs(&obj); /* fill in length field, if any */ - } - else - { - /* We set outs->cur to outs->roof so that - * any attempt to output something into outs - * before obj is closed will trigger an error. - */ - outs->cur = outs->roof; - - *obj_pbs = obj; - } - return TRUE; - - default: - bad_case(fp->field_type); - } - } - } - - /* some failure got us here: report it */ - loglog(RC_LOG_SERIOUS, ugh); /* ??? serious, but errno not relevant */ - return FALSE; -} - -bool -out_generic(u_int8_t np, struct_desc *sd -, pb_stream *outs, pb_stream *obj_pbs) -{ - struct isakmp_generic gen; - - passert(sd->fields == isakmp_generic_desc.fields); - gen.isag_np = np; - return out_struct(&gen, sd, outs, obj_pbs); -} - -bool -out_generic_raw(u_int8_t np, struct_desc *sd -, pb_stream *outs, const void *bytes, size_t len, const char *name) -{ - pb_stream pbs; - - if (!out_generic(np, sd, outs, &pbs) - || !out_raw(bytes, len, &pbs, name)) - return FALSE; - close_output_pbs(&pbs); - return TRUE; -} - -bool -out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name) -{ - if (pbs_left(outs) < len) - { - loglog(RC_LOG_SERIOUS, "not enough room left to place %lu bytes of %s in %s" - , (unsigned long) len, name, outs->name); - return FALSE; - } - else - { - DBG(DBG_EMITTING - , DBG_log("emitting %u raw bytes of %s into %s" - , (unsigned) len, name, outs->name); - DBG_dump(name, bytes, len)); - memcpy(outs->cur, bytes, len); - outs->cur += len; - return TRUE; - } -} - -bool -out_zero(size_t len, pb_stream *outs, const char *name) -{ - if (pbs_left(outs) < len) - { - loglog(RC_LOG_SERIOUS, "not enough room left to place %s in %s", name, outs->name); - return FALSE; - } - else - { - DBG(DBG_EMITTING, DBG_log("emitting %u zero bytes of %s into %s" - , (unsigned) len, name, outs->name)); - memset(outs->cur, 0x00, len); - outs->cur += len; - return TRUE; - } -} - -/* Record current length. - * Note: currently, this may be repeated any number of times; - * the last one wins. - */ -void -close_output_pbs(pb_stream *pbs) -{ - if (pbs->lenfld != NULL) - { - u_int32_t len = pbs_offset(pbs); - int i = pbs->lenfld_desc->size; - - if (pbs->lenfld_desc->field_type == ft_lv) - len -= sizeof(struct isakmp_attribute); - DBG(DBG_EMITTING, DBG_log("emitting length of %s: %lu" - , pbs->name, (unsigned long) len)); - while (i-- != 0) - { - pbs->lenfld[i] = (u_int8_t)len; - len >>= BITS_PER_BYTE; - } - } - if (pbs->container != NULL) - pbs->container->cur = pbs->cur; /* pass space utilization up */ -} diff --git a/src/pluto/packet.h b/src/pluto/packet.h deleted file mode 100644 index 1510b81a0..000000000 --- a/src/pluto/packet.h +++ /dev/null @@ -1,653 +0,0 @@ -/* parsing packets: formats and tools - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PACKET_H -#define _PACKET_H - -/* a struct_desc describes a structure for the struct I/O routines. - * This requires arrays of field_desc values to describe struct fields. - */ - -typedef const struct struct_desc { - const char *name; - const struct field_desc *fields; - size_t size; -} struct_desc; - -/* Note: if an ft_af_enum field has the ISAKMP_ATTR_AF_TV bit set, - * the subsequent ft_lv field will be interpreted as an immediate value. - * This matches how attributes are encoded. - * See RFC 2408 "ISAKMP" 3.3 - */ - -enum field_type { - ft_mbz, /* must be zero */ - ft_nat, /* natural number (may be 0) */ - ft_len, /* length of this struct and any following crud */ - ft_lv, /* length/value field of attribute */ - ft_enum, /* value from an enumeration */ - ft_loose_enum, /* value from an enumeration with only some names known */ - ft_af_loose_enum, /* Attribute Format + enumeration, some names known */ - ft_af_enum, /* Attribute Format + value from an enumeration */ - ft_set, /* bits representing set */ - ft_raw, /* bytes to be left in network-order */ - ft_end, /* end of field list */ -}; - -typedef const struct field_desc { - enum field_type field_type; - int size; /* size, in bytes, of field */ - const char *name; - const void *desc; /* enum_names for enum or char *[] for bits */ -} field_desc; - -/* The formatting of input and output of packets is done - * through packet_byte_stream objects. - * These describe a stream of bytes in memory. - * Several routines are provided to manipulate these objects - * Actual packet transfer is done elsewhere. - */ -typedef struct packet_byte_stream { - struct packet_byte_stream *container; /* PBS of which we are part */ - struct_desc *desc; - const char *name; /* what does this PBS represent? */ - u_int8_t - *start, - *cur, /* current position in stream */ - *roof; /* byte after last in PBS (actually just a limit on output) */ - /* For an output PBS, the length field will be filled in later so - * we need to record its particulars. Note: it may not be aligned. - */ - u_int8_t *lenfld; - field_desc *lenfld_desc; -} pb_stream; - -/* For an input PBS, pbs_offset is amount of stream processed. - * For an output PBS, pbs_offset is current size of stream. - * For an input PBS, pbs_room is size of stream. - * For an output PBS, pbs_room is maximum size allowed. - */ -#define pbs_offset(pbs) ((size_t)((pbs)->cur - (pbs)->start)) -#define pbs_room(pbs) ((size_t)((pbs)->roof - (pbs)->start)) -#define pbs_left(pbs) ((size_t)((pbs)->roof - (pbs)->cur)) - -extern void init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name); - -extern bool in_struct(void *struct_ptr, struct_desc *sd, - pb_stream *ins, pb_stream *obj_pbs); -extern bool in_raw(void *bytes, size_t len, pb_stream *ins, const char *name); - -extern bool out_struct(const void *struct_ptr, struct_desc *sd, - pb_stream *outs, pb_stream *obj_pbs); -extern bool out_generic(u_int8_t np, struct_desc *sd, - pb_stream *outs, pb_stream *obj_pbs); -extern bool out_generic_raw(u_int8_t np, struct_desc *sd, - pb_stream *outs, const void *bytes, size_t len, const char *name); -#define out_generic_chunk(np, sd, outs, ch, name) \ - out_generic_raw(np, sd, outs, (ch).ptr, (ch).len, name) -extern bool out_zero(size_t len, pb_stream *outs, const char *name); -extern bool out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name); -#define out_chunk(ch, outs, name) out_raw((ch).ptr, (ch).len, (outs), (name)) -extern void close_output_pbs(pb_stream *pbs); - -#ifdef DEBUG -extern void DBG_print_struct(const char *label, const void *struct_ptr, - struct_desc *sd, bool len_meaningful); -#endif - -/* ISAKMP Header: for all messages - * layout from RFC 2408 "ISAKMP" section 3.1 - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Initiator ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Responder ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Message ID ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * Although the drafts are a little unclear, there are a few - * places that specify that messages should be padded with 0x00 - * octets (bytes) to make the length a multiple of something. - * - * RFC 2408 "ISAKMP" 3.6 specifies that all messages will be - * padded to be a multiple of 4 octets in length. - * ??? This looks vestigial, and we ignore this requirement. - * - * RFC 2409 "IKE" Appedix B specifies: - * Each message should be padded up to the nearest block size - * using bytes containing 0x00. - * ??? This does not appear to be limited to encrypted messages, - * but it surely must be: the block size is meant to be the encryption - * block size, and that is meaningless for a non-encrypted message. - * - * RFC 2409 "IKE" 5.3 specifies: - * Encrypted payloads are padded up to the nearest block size. - * All padding bytes, except for the last one, contain 0x00. The - * last byte of the padding contains the number of the padding - * bytes used, excluding the last one. Note that this means there - * will always be padding. - * ??? This is nuts since payloads are not padded, messages are. - * It also contradicts Appendix B. So we ignore it. - * - * Summary: we pad encrypted output messages with 0x00 to bring them - * up to a multiple of the encryption block size. On input, we require - * that any encrypted portion of a message be a multiple of the encryption - * block size. After any decryption, we ignore padding (any bytes after - * the first payload that specifies a next payload of none; we don't - * require them to be zero). - */ - -struct isakmp_hdr -{ - u_int8_t isa_icookie[COOKIE_SIZE]; - u_int8_t isa_rcookie[COOKIE_SIZE]; - u_int8_t isa_np; /* Next payload */ - u_int8_t isa_version; /* high-order 4 bits: Major; low order 4: Minor */ -#define ISA_MAJ_SHIFT 4 -#define ISA_MIN_MASK (~((~0u) << ISA_MAJ_SHIFT)) - u_int8_t isa_xchg; /* Exchange type */ - u_int8_t isa_flags; - u_int32_t isa_msgid; /* Message ID (RAW) */ - u_int32_t isa_length; /* Length of message */ -}; - -extern struct_desc isakmp_hdr_desc; - -/* Generic portion of all ISAKMP payloads. - * layout from RFC 2408 "ISAKMP" section 3.2 - * This describes the first 32-bit chunk of all payloads. - * The previous next payload depends on the actual payload type. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_generic -{ - u_int8_t isag_np; - u_int8_t isag_reserved; - u_int16_t isag_length; -}; - -extern struct_desc isakmp_generic_desc; - -/* ISAKMP Data Attribute (generic representation within payloads) - * layout from RFC 2408 "ISAKMP" section 3.3 - * This is not a payload type. - * In TLV format, this is followed by a value field. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * !A! Attribute Type ! AF=0 Attribute Length ! - * !F! ! AF=1 Attribute Value ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . AF=0 Attribute Value . - * . AF=1 Not Transmitted . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_attribute -{ - /* The high order bit of isaat_af_type is the Attribute Format - * If it is off, the format is TLV: lv is the length of the following - * attribute value. - * If it is on, the format is TV: lv is the value of the attribute. - * ISAKMP_ATTR_AF_MASK is the mask in host form. - * - * The low order 15 bits of isaat_af_type is the Attribute Type. - * ISAKMP_ATTR_RTYPE_MASK is the mask in host form. - */ - u_int16_t isaat_af_type; /* high order bit: AF; lower 15: rtype */ - u_int16_t isaat_lv; /* Length or value */ -}; - -#define ISAKMP_ATTR_AF_MASK 0x8000 -#define ISAKMP_ATTR_AF_TV ISAKMP_ATTR_AF_MASK /* value in lv */ -#define ISAKMP_ATTR_AF_TLV 0 /* length in lv; value follows */ - -#define ISAKMP_ATTR_RTYPE_MASK 0x7FFF - -extern struct_desc - isakmp_oakley_attribute_desc, - isakmp_ipsec_attribute_desc; - -/* ISAKMP Security Association Payload - * layout from RFC 2408 "ISAKMP" section 3.4 - * A variable length Situation follows. - * Previous next payload: ISAKMP_NEXT_SA - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Situation ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_sa -{ - u_int8_t isasa_np; /* Next payload */ - u_int8_t isasa_reserved; - u_int16_t isasa_length; /* Payload length */ - u_int32_t isasa_doi; /* DOI */ -}; - -extern struct_desc isakmp_sa_desc; - -extern struct_desc ipsec_sit_desc; - -/* ISAKMP Proposal Payload - * layout from RFC 2408 "ISAKMP" section 3.5 - * A variable length SPI follows. - * Previous next payload: ISAKMP_NEXT_P - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! SPI (variable) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_proposal -{ - u_int8_t isap_np; - u_int8_t isap_reserved; - u_int16_t isap_length; - u_int8_t isap_proposal; - u_int8_t isap_protoid; - u_int8_t isap_spisize; - u_int8_t isap_notrans; /* Number of transforms */ -}; - -extern struct_desc isakmp_proposal_desc; - -/* ISAKMP Transform Payload - * layout from RFC 2408 "ISAKMP" section 3.6 - * Variable length SA Attributes follow. - * Previous next payload: ISAKMP_NEXT_T - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Transform # ! Transform-Id ! RESERVED2 ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ SA Attributes ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_transform -{ - u_int8_t isat_np; - u_int8_t isat_reserved; - u_int16_t isat_length; - u_int8_t isat_transnum; /* Number of the transform */ - u_int8_t isat_transid; - u_int16_t isat_reserved2; -}; - -extern struct_desc - isakmp_isakmp_transform_desc, - isakmp_ah_transform_desc, - isakmp_esp_transform_desc, - isakmp_ipcomp_transform_desc; - -/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.7 - * Variable Key Exchange Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_KE - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Key Exchange Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_keyex_desc; - -/* ISAKMP Identification Payload - * layout from RFC 2408 "ISAKMP" section 3.8 - * See "struct identity" declared later. - * Variable length Identification Data follow. - * Previous next payload: ISAKMP_NEXT_ID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! DOI Specific ID Data ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Identification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_id -{ - u_int8_t isaid_np; - u_int8_t isaid_reserved; - u_int16_t isaid_length; - u_int8_t isaid_idtype; - u_int8_t isaid_doi_specific_a; - u_int16_t isaid_doi_specific_b; -}; - -extern struct_desc isakmp_identification_desc; - -/* IPSEC Identification Payload Content - * layout from RFC 2407 "IPsec DOI" section 4.6.2 - * See struct isakmp_id declared earlier. - * Note: Hashing skips the ISAKMP generic payload header - * Variable length Identification Data follow. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! Protocol ID ! Port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Identification Data ~ - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_ipsec_id -{ - u_int8_t isaiid_np; - u_int8_t isaiid_reserved; - u_int16_t isaiid_length; - u_int8_t isaiid_idtype; - u_int8_t isaiid_protoid; - u_int16_t isaiid_port; -}; - -extern struct_desc isakmp_ipsec_identification_desc; - -/* ISAKMP Certificate Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.9 - * Variable length Certificate Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_CERT. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert Encoding ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_cert -{ - u_int8_t isacert_np; - u_int8_t isacert_reserved; - u_int16_t isacert_length; - u_int8_t isacert_type; -}; - -/* NOTE: this packet type has a fixed portion that is not a - * multiple of 4 octets. This means that sizeof(struct isakmp_cert) - * yields the wrong value for the length. - */ -#define ISAKMP_CERT_SIZE 5 - -extern struct_desc isakmp_ipsec_certificate_desc; - -/* ISAKMP Certificate Request Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.10 - * Variable length Certificate Types and Certificate Authorities follow. - * Previous next payload: ISAKMP_NEXT_CR. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert. Type ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Authority ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_cr -{ - u_int8_t isacr_np; - u_int8_t isacr_reserved; - u_int16_t isacr_length; - u_int8_t isacr_type; -}; - -/* NOTE: this packet type has a fixed portion that is not a - * multiple of 4 octets. This means that sizeof(struct isakmp_cr) - * yields the wrong value for the length. - */ -#define ISAKMP_CR_SIZE 5 - -extern struct_desc isakmp_ipsec_cert_req_desc; - -/* ISAKMP Hash Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.11 - * Variable length Hash Data follow. - * Previous next payload: ISAKMP_NEXT_HASH. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Hash Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_hash_desc; - -/* ISAKMP Signature Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.12 - * Variable length Signature Data follow. - * Previous next payload: ISAKMP_NEXT_SIG. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Signature Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_signature_desc; - -/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.13 - * Variable length Nonce Data follow. - * Previous next payload: ISAKMP_NEXT_NONCE. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Nonce Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_nonce_desc; - -/* ISAKMP Notification Payload - * layout from RFC 2408 "ISAKMP" section 3.14 - * This is followed by a variable length SPI - * and then possibly by variable length Notification Data. - * Previous next payload: ISAKMP_NEXT_N - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-ID ! SPI Size ! Notify Message Type ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Notification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_notification -{ - u_int8_t isan_np; - u_int8_t isan_reserved; - u_int16_t isan_length; - u_int32_t isan_doi; - u_int8_t isan_protoid; - u_int8_t isan_spisize; - u_int16_t isan_type; -}; - -extern struct_desc isakmp_notification_desc; - -/* ISAKMP Delete Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length SPI. - * Previous next payload: ISAKMP_NEXT_D - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-Id ! SPI Size ! # of SPIs ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index(es) (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_delete -{ - u_int8_t isad_np; - u_int8_t isad_reserved; - u_int16_t isad_length; - u_int32_t isad_doi; - u_int8_t isad_protoid; - u_int8_t isad_spisize; - u_int16_t isad_nospi; -}; - -extern struct_desc isakmp_delete_desc; - -/* From draft-dukes-ike-mode-cfg -3.2. Attribute Payload - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Next Payload ! RESERVED ! Payload Length ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Type ! RESERVED ! Identifier ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! ! - ! ! - ~ Attributes ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ -struct isakmp_mode_attr -{ - u_int8_t isama_np; - u_int8_t isama_reserved; - u_int16_t isama_length; - u_int8_t isama_type; - u_int8_t isama_reserved2; - u_int16_t isama_identifier; -}; - -extern struct_desc isakmp_attr_desc; -extern struct_desc isakmp_modecfg_attribute_desc; - -/* ISAKMP Vendor ID Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length VID. - * Previous next payload: ISAKMP_NEXT_VID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Vendor ID (VID) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_vendor_id_desc; - -struct isakmp_nat_oa -{ - u_int8_t isanoa_np; - u_int8_t isanoa_reserved_1; - u_int16_t isanoa_length; - u_int8_t isanoa_idtype; - u_int8_t isanoa_reserved_2; - u_int16_t isanoa_reserved_3; -}; - -extern struct_desc isakmp_nat_d; -extern struct_desc isakmp_nat_oa; - -/* union of all payloads */ - -union payload { - struct isakmp_generic generic; - struct isakmp_sa sa; - struct isakmp_proposal proposal; - struct isakmp_transform transform; - struct isakmp_id id; /* Main Mode */ - struct isakmp_cert cert; - struct isakmp_cr cr; - struct isakmp_ipsec_id ipsec_id; /* Quick Mode */ - struct isakmp_notification notification; - struct isakmp_delete delete; - struct isakmp_nat_oa nat_oa; - struct isakmp_mode_attr attribute; -}; - -/* descriptor for each payload type - * - * There is a slight problem in that some payloads differ, depending - * on the mode. Since this is table only used for top-level payloads, - * Proposal and Transform payloads need not be handled. - * That leaves only Identification payloads as a problem. - * We make all these entries NULL - */ -extern struct_desc *const payload_descs[ISAKMP_NEXT_ROOF]; - -#endif /* _PACKET_H */ diff --git a/src/pluto/pkcs7.c b/src/pluto/pkcs7.c deleted file mode 100644 index 10b2a4d5a..000000000 --- a/src/pluto/pkcs7.c +++ /dev/null @@ -1,755 +0,0 @@ -/* Support of PKCS#7 data structures - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pkcs7.h" - -const contentInfo_t empty_contentInfo = { - OID_UNKNOWN , /* type */ - { NULL, 0 } /* content */ -}; - -/** - * ASN.1 definition of the PKCS#7 ContentInfo type - */ -static const asn1Object_t contentInfoObjects[] = { - { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */ - { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_INFO_TYPE 1 -#define PKCS7_INFO_CONTENT 2 - -/** - * ASN.1 definition of the PKCS#7 signedData type - */ -static const asn1Object_t signedDataObjects[] = { - { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */ - { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ - { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */ - { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 6 */ - { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */ - { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */ - { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_LOOP }, /* 9 */ - { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ - { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */ - { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */ - { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */ - { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */ - { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */ - { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 19 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ - { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */ - { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */ - { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_SIGNED_VERSION 1 -#define PKCS7_DIGEST_ALG 3 -#define PKCS7_SIGNED_CONTENT_INFO 5 -#define PKCS7_SIGNED_CERT 7 -#define PKCS7_SIGNER_INFO 13 -#define PKCS7_SIGNER_INFO_VERSION 14 -#define PKCS7_SIGNED_ISSUER 16 -#define PKCS7_SIGNED_SERIAL_NUMBER 17 -#define PKCS7_DIGEST_ALGORITHM 18 -#define PKCS7_AUTH_ATTRIBUTES 19 -#define PKCS7_DIGEST_ENC_ALGORITHM 21 -#define PKCS7_ENCRYPTED_DIGEST 22 - -/** - * ASN.1 definition of the PKCS#7 envelopedData type - */ -static const asn1Object_t envelopedDataObjects[] = { - { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */ - { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */ - { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */ - { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ - { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ - { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */ - { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */ - { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 14 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_ENVELOPED_VERSION 1 -#define PKCS7_RECIPIENT_INFO_VERSION 4 -#define PKCS7_ISSUER 6 -#define PKCS7_SERIAL_NUMBER 7 -#define PKCS7_ENCRYPTION_ALG 8 -#define PKCS7_ENCRYPTED_KEY 9 -#define PKCS7_CONTENT_TYPE 12 -#define PKCS7_CONTENT_ENC_ALGORITHM 13 -#define PKCS7_ENCRYPTED_CONTENT 14 -#define PKCS7_ENVELOPED_ROOF 15 - -/** - * Parse PKCS#7 ContentInfo object - */ -bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - bool success = FALSE; - - parser = asn1_parser_create(contentInfoObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == PKCS7_INFO_TYPE) - { - cInfo->type = asn1_known_oid(object); - if (cInfo->type < OID_PKCS7_DATA - || cInfo->type > OID_PKCS7_ENCRYPTED_DATA) - { - DBG1(DBG_LIB, "unknown pkcs7 content type"); - goto end; - } - } - else if (objectID == PKCS7_INFO_CONTENT) - { - cInfo->content = object; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - return success; -} - -/** - * Parse a PKCS#7 signedData object - */ -bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, - linked_list_t *certs, - chunk_t *attributes, certificate_t *cacert) -{ - asn1_parser_t *parser; - chunk_t object; - int digest_alg = OID_UNKNOWN; - int enc_alg = OID_UNKNOWN; - int signerInfos = 0; - int version; - int objectID; - bool success = FALSE; - - contentInfo_t cInfo = empty_contentInfo; - chunk_t encrypted_digest = chunk_empty; - - if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) - { - return FALSE; - } - if (cInfo.type != OID_PKCS7_SIGNED_DATA) - { - DBG1(DBG_LIB, "pkcs7 content type is not signedData"); - return FALSE; - } - - parser = asn1_parser_create(signedDataObjects, cInfo.content); - parser->set_top_level(parser, 2); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser); - - switch (objectID) - { - case PKCS7_SIGNED_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - break; - case PKCS7_DIGEST_ALG: - digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_SIGNED_CONTENT_INFO: - if (data != NULL) - { - pkcs7_parse_contentInfo(object, level, data); - } - break; - case PKCS7_SIGNED_CERT: - { - certificate_t *cert; - - DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate"); - cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, object, - BUILD_END); - if (cert) - { - certs->insert_last(certs, cert); - } - } - break; - case PKCS7_SIGNER_INFO: - signerInfos++; - DBG2(DBG_LIB, " signer #%d", signerInfos); - break; - case PKCS7_SIGNER_INFO_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - break; - case PKCS7_SIGNED_ISSUER: - { - identification_t *issuer = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " \"%Y\"", issuer); - issuer->destroy(issuer); - break; - } - case PKCS7_AUTH_ATTRIBUTES: - if (attributes != NULL) - { - *attributes = object; - *attributes->ptr = ASN1_SET; - } - break; - case PKCS7_DIGEST_ALGORITHM: - digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_DIGEST_ENC_ALGORITHM: - enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_ENCRYPTED_DIGEST: - encrypted_digest = object; - } - } - success = parser->success(parser); - parser->destroy(parser); - if (!success) - { - return FALSE; - } - - /* check the signature only if a cacert is available */ - if (cacert != NULL) - { - public_key_t *key; - signature_scheme_t scheme; - - scheme = signature_scheme_from_oid(digest_alg); - if (scheme == SIGN_UNKNOWN) - { - DBG1(DBG_LIB, "unsupported signature scheme"); - return FALSE; - } - if (signerInfos == 0) - { - DBG1(DBG_LIB, "no signerInfo object found"); - return FALSE; - } - else if (signerInfos > 1) - { - DBG1(DBG_LIB, "more than one signerInfo object found"); - return FALSE; - } - if (attributes->ptr == NULL) - { - DBG1(DBG_LIB, "no authenticatedAttributes object found"); - return FALSE; - } - if (enc_alg != OID_RSA_ENCRYPTION) - { - DBG1(DBG_LIB, "only RSA digest encryption supported"); - return FALSE; - } - - /* verify the signature */ - key = cacert->get_public_key(cacert); - if (key == NULL) - { - DBG1(DBG_LIB, "no public key found in CA certificate"); - return FALSE; - } - if (key->verify(key, scheme, *attributes, encrypted_digest)) - { - DBG2(DBG_LIB, "signature is valid"); - } - else - { - DBG1(DBG_LIB, "invalid signature"); - success = FALSE; - } - key->destroy(key); - } - return success; -} - -/** - * Parse a PKCS#7 envelopedData object - */ -bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, - chunk_t serialNumber, - private_key_t *key) -{ - asn1_parser_t *parser; - chunk_t object; - chunk_t iv = chunk_empty; - chunk_t symmetric_key = chunk_empty; - chunk_t encrypted_content = chunk_empty; - - crypter_t *crypter = NULL; - - int enc_alg = OID_UNKNOWN; - int content_enc_alg = OID_UNKNOWN; - int version; - int objectID; - bool success = FALSE; - - contentInfo_t cInfo = empty_contentInfo; - *data = chunk_empty; - - if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) - { - goto failed; - } - if (cInfo.type != OID_PKCS7_ENVELOPED_DATA) - { - DBG1(DBG_LIB, "pkcs7 content type is not envelopedData"); - goto failed; - } - - parser = asn1_parser_create(envelopedDataObjects, cInfo.content); - parser->set_top_level(parser, 2); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser); - - switch (objectID) - { - case PKCS7_ENVELOPED_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - if (version != 0) - { - DBG1(DBG_LIB, "envelopedData version is not 0"); - goto end; - } - break; - case PKCS7_RECIPIENT_INFO_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - if (version != 0) - { - DBG1(DBG_LIB, "recipient info version is not 0"); - goto end; - } - break; - case PKCS7_ISSUER: - { - identification_t *issuer = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " \"%Y\"", issuer); - issuer->destroy(issuer); - break; - } - case PKCS7_SERIAL_NUMBER: - if (!chunk_equals(serialNumber, object)) - { - DBG1(DBG_LIB, "serial numbers do not match"); - goto end; - } - break; - case PKCS7_ENCRYPTION_ALG: - enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - if (enc_alg != OID_RSA_ENCRYPTION) - { - DBG1(DBG_LIB, "only rsa encryption supported"); - goto end; - } - break; - case PKCS7_ENCRYPTED_KEY: - if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key)) - { - DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa"); - goto end; - } - DBG4(DBG_LIB, "symmetric key %B", &symmetric_key); - break; - case PKCS7_CONTENT_TYPE: - if (asn1_known_oid(object) != OID_PKCS7_DATA) - { - DBG1(DBG_LIB, "encrypted content not of type pkcs7 data"); - goto end; - } - break; - case PKCS7_CONTENT_ENC_ALGORITHM: - content_enc_alg = asn1_parse_algorithmIdentifier(object, level, &iv); - - if (content_enc_alg == OID_UNKNOWN) - { - DBG1(DBG_LIB, "unknown content encryption algorithm"); - goto end; - } - if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV")) - { - DBG1(DBG_LIB, "IV could not be parsed"); - goto end; - } - break; - case PKCS7_ENCRYPTED_CONTENT: - encrypted_content = object; - break; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - if (!success) - { - goto failed; - } - success = FALSE; - - /* decrypt the content */ - { - encryption_algorithm_t alg; - size_t key_size; - crypter_t *crypter; - - alg = encryption_algorithm_from_oid(content_enc_alg, &key_size); - if (alg == ENCR_UNDEFINED) - { - DBG1(DBG_LIB, "unsupported content encryption algorithm"); - goto failed; - } - crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); - if (crypter == NULL) - { - DBG1(DBG_LIB, "crypter %N not available", encryption_algorithm_names, alg); - goto failed; - } - if (symmetric_key.len != crypter->get_key_size(crypter)) - { - DBG1(DBG_LIB, "symmetric key length %d is wrong", symmetric_key.len); - goto failed; - } - if (iv.len != crypter->get_iv_size(crypter)) - { - DBG1(DBG_LIB, "IV length %d is wrong", iv.len); - goto failed; - } - crypter->set_key(crypter, symmetric_key); - crypter->decrypt(crypter, encrypted_content, iv, data); - DBG4(DBG_LIB, "decrypted content with padding: %B", data); - } - - /* remove the padding */ - { - u_char *pos = data->ptr + data->len - 1; - u_char pattern = *pos; - size_t padding = pattern; - - if (padding > data->len) - { - DBG1(DBG_LIB, "padding greater than data length"); - goto failed; - } - data->len -= padding; - - while (padding-- > 0) - { - if (*pos-- != pattern) - { - DBG1(DBG_LIB, "wrong padding pattern"); - goto failed; - } - } - } - success = TRUE; - -failed: - DESTROY_IF(crypter); - chunk_clear(&symmetric_key); - if (!success) - { - free(data->ptr); - } - return success; -} - -/** - * @brief Builds a contentType attribute - * - * @return ASN.1 encoded contentType attribute - */ -chunk_t pkcs7_contentType_attribute(void) -{ - return asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(OID_PKCS9_CONTENT_TYPE), - asn1_wrap(ASN1_SET, "m", - asn1_build_known_oid(OID_PKCS7_DATA))); -} - -/** - * @brief Builds a messageDigest attribute - * - * - * @param[in] blob content to create digest of - * @param[in] digest_alg digest algorithm to be used - * @return ASN.1 encoded messageDigest attribute - * - */ -chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg) -{ - chunk_t digest; - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = hasher_algorithm_from_oid(digest_alg); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - hasher->allocate_hash(hasher, content, &digest); - hasher->destroy(hasher); - - return asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(OID_PKCS9_MESSAGE_DIGEST), - asn1_wrap(ASN1_SET, "m", - asn1_wrap(ASN1_OCTET_STRING, "m", digest))); -} - -/** - * build a DER-encoded contentInfo object - */ -static chunk_t pkcs7_build_contentInfo(contentInfo_t *cInfo) -{ - return (cInfo->content.ptr) ? - asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(cInfo->type), - asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content)) : - asn1_build_known_oid(cInfo->type); -} - -/** - * build issuerAndSerialNumber object - */ -chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert) -{ - identification_t *issuer = cert->get_issuer(cert); - x509_t *x509 = (x509_t*)cert; - - return asn1_wrap(ASN1_SEQUENCE, "cm", - issuer->get_encoding(issuer), - asn1_integer("c", x509->get_serial(x509))); -} - -/** - * create a signed pkcs7 contentInfo object - */ -chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - certificate_t *cert, int digest_alg, - private_key_t *key) -{ - contentInfo_t pkcs7Data, signedData; - chunk_t authenticatedAttributes = chunk_empty; - chunk_t encryptedDigest = chunk_empty; - chunk_t signerInfo, cInfo, signature, encoding = chunk_empty;; - signature_scheme_t scheme = signature_scheme_from_oid(digest_alg); - - if (attributes.ptr) - { - if (key->sign(key, scheme, attributes, &signature)) - { - encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); - authenticatedAttributes = chunk_clone(attributes); - *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; - } - } - else if (data.ptr) - { - if (key->sign(key, scheme, data, &signature)) - { - encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); - } - } - signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm" - , ASN1_INTEGER_1 - , pkcs7_build_issuerAndSerialNumber(cert) - , asn1_algorithmIdentifier(digest_alg) - , authenticatedAttributes - , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) - , encryptedDigest); - - pkcs7Data.type = OID_PKCS7_DATA; - pkcs7Data.content = (data.ptr == NULL)? chunk_empty - : asn1_simple_object(ASN1_OCTET_STRING, data); - - cert->get_encoding(cert, CERT_ASN1_DER, &encoding); - signedData.type = OID_PKCS7_SIGNED_DATA; - signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm" - , ASN1_INTEGER_1 - , asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_alg)) - , pkcs7_build_contentInfo(&pkcs7Data) - , asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding) - , asn1_wrap(ASN1_SET, "m", signerInfo)); - - cInfo = pkcs7_build_contentInfo(&signedData); - DBG3(DBG_LIB, "signedData %B", &cInfo); - - free(pkcs7Data.content.ptr); - free(signedData.content.ptr); - return cInfo; -} - -/** - * create a symmetrically encrypted pkcs7 contentInfo object - */ -chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg) -{ - encryption_algorithm_t alg; - size_t alg_key_size; - chunk_t symmetricKey, protectedKey, iv, in, out; - crypter_t *crypter; - - alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size); - crypter = lib->crypto->create_crypter(lib->crypto, alg, - alg_key_size/BITS_PER_BYTE); - if (crypter == NULL) - { - DBG1(DBG_LIB, "crypter for %N not available", encryption_algorithm_names, alg); - return chunk_empty; - } - - /* generate a true random symmetric encryption key and a pseudo-random iv */ - { - rng_t *rng; - - rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); - rng->allocate_bytes(rng, crypter->get_key_size(crypter), &symmetricKey); - DBG4(DBG_LIB, "symmetric encryption key %B", &symmetricKey); - rng->destroy(rng); - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->allocate_bytes(rng, crypter->get_iv_size(crypter), &iv); - DBG4(DBG_LIB, "initialization vector: %B", &iv); - rng->destroy(rng); - } - - /* pad the data to a multiple of the block size */ - { - size_t block_size = crypter->get_block_size(crypter); - size_t padding = block_size - data.len % block_size; - - in.len = data.len + padding; - in.ptr = malloc(in.len); - - DBG2(DBG_LIB, "padding %u bytes of data to multiple block size of %u bytes", - data.len, in.len); - - /* copy data */ - memcpy(in.ptr, data.ptr, data.len); - /* append padding */ - memset(in.ptr + data.len, padding, padding); - } - DBG3(DBG_LIB, "padded unencrypted data %B", &in); - - /* symmetric encryption of data object */ - crypter->set_key(crypter, symmetricKey); - crypter->encrypt(crypter, in, iv, &out); - crypter->destroy(crypter); - chunk_clear(&in); - DBG3(DBG_LIB, "encrypted data %B", &out); - - /* protect symmetric key by public key encryption */ - { - public_key_t *key = cert->get_public_key(cert); - - if (key == NULL) - { - DBG1(DBG_LIB, "public key not found in encryption certificate"); - chunk_clear(&symmetricKey); - chunk_free(&iv); - chunk_free(&out); - return chunk_empty; - } - key->encrypt(key, ENCRYPT_RSA_PKCS1, symmetricKey, &protectedKey); - key->destroy(key); - } - - /* build pkcs7 enveloped data object */ - { - - chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_build_known_oid(enc_alg) - , asn1_simple_object(ASN1_OCTET_STRING, iv)); - - chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm" - , asn1_build_known_oid(OID_PKCS7_DATA) - , contentEncryptionAlgorithm - , asn1_wrap(ASN1_CONTEXT_S_0, "m", out)); - - chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m" - , protectedKey); - - chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm" - , ASN1_INTEGER_0 - , pkcs7_build_issuerAndSerialNumber(cert) - , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) - , encryptedKey); - - chunk_t cInfo; - contentInfo_t envelopedData; - - envelopedData.type = OID_PKCS7_ENVELOPED_DATA; - envelopedData.content = asn1_wrap(ASN1_SEQUENCE, "cmm" - , ASN1_INTEGER_0 - , asn1_wrap(ASN1_SET, "m", recipientInfo) - , encryptedContentInfo); - - cInfo = pkcs7_build_contentInfo(&envelopedData); - DBG3(DBG_LIB, "envelopedData %B", &cInfo); - - chunk_free(&envelopedData.content); - chunk_free(&iv); - chunk_clear(&symmetricKey); - return cInfo; - } -} diff --git a/src/pluto/pkcs7.h b/src/pluto/pkcs7.h deleted file mode 100644 index 1743ea9c4..000000000 --- a/src/pluto/pkcs7.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Support of PKCS#7 data structures - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-2009 Andreas Steffen - * - * Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PKCS7_H -#define _PKCS7_H - -#include -#include -#include -#include - -/* Access structure for a PKCS#7 ContentInfo object */ - -typedef struct contentInfo contentInfo_t; - -struct contentInfo { - int type; - chunk_t content; -}; - -extern const contentInfo_t empty_contentInfo; - -extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, - contentInfo_t *cInfo); -extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, - linked_list_t *cert, chunk_t *attributes, - certificate_t *cacert); -extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, - chunk_t serialNumber, private_key_t *key); -extern chunk_t pkcs7_contentType_attribute(void); -extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg); -extern chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert); -extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - certificate_t *cert, int digest_alg, - private_key_t *key); -extern chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, - int enc_alg); - -#endif /* _PKCS7_H */ diff --git a/src/pluto/plugin_list.c b/src/pluto/plugin_list.c deleted file mode 100644 index ae060ac90..000000000 --- a/src/pluto/plugin_list.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2011 Martin Willi, revosec AG - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include -#include - -/** - * List loaded plugin information - */ -void plugin_list(void) -{ - plugin_feature_t *features, *fp; - enumerator_t *enumerator; - linked_list_t *list; - plugin_t *plugin; - int count, i; - bool loaded; - char *str; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of loaded Plugins:"); - whack_log(RC_COMMENT, " "); - - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (enumerator->enumerate(enumerator, &plugin, &list)) - { - whack_log(RC_COMMENT, "%s:", plugin->get_name(plugin)); - if (plugin->get_features) - { - count = plugin->get_features(plugin, &features); - for (i = 0; i < count; i++) - { - str = plugin_feature_get_string(&features[i]); - switch (features[i].kind) - { - case FEATURE_PROVIDE: - fp = &features[i]; - loaded = list->find_first(list, NULL, - (void**)&fp) == SUCCESS; - whack_log(RC_COMMENT, " %s%s", - str, loaded ? "" : " (not loaded)"); - break; - case FEATURE_DEPENDS: - whack_log(RC_COMMENT, " %s", str); - break; - case FEATURE_SDEPEND: - whack_log(RC_COMMENT, " %s (soft)", str); - break; - default: - break; - } - free(str); - } - } - } - enumerator->destroy(enumerator); -} diff --git a/src/pluto/plugin_list.h b/src/pluto/plugin_list.h deleted file mode 100644 index 62e4a167d..000000000 --- a/src/pluto/plugin_list.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Generates a list of all loaded plugins and their dependencies - * Copyright (C) 2011 Andreas Steffen - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PLUGIN_LIST_H -#define _PLUGIN_LIST_H - -extern void plugin_list(void); - -#endif /* _PLUGIN_LIST_H */ diff --git a/src/pluto/plugins/xauth/Makefile.am b/src/pluto/plugins/xauth/Makefile.am deleted file mode 100644 index 354325b35..000000000 --- a/src/pluto/plugins/xauth/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ - -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/whack \ - -I$(top_srcdir)/src/pluto - -AM_CFLAGS = -rdynamic - -plugin_LTLIBRARIES = libstrongswan-xauth.la - -libstrongswan_xauth_la_SOURCES = \ - xauth_plugin.h xauth_plugin.c \ - xauth_default_provider.c xauth_default_provider.h \ - xauth_default_verifier.c xauth_default_verifier.h - -libstrongswan_xauth_la_LDFLAGS = -module -avoid-version diff --git a/src/pluto/plugins/xauth/xauth_default_provider.c b/src/pluto/plugins/xauth/xauth_default_provider.c deleted file mode 100644 index 77c5facc4..000000000 --- a/src/pluto/plugins/xauth/xauth_default_provider.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "xauth_default_provider.h" - -typedef struct private_xauth_default_provider_t private_xauth_default_provider_t; - -/** - * private data of xauth_default_provider - */ -struct private_xauth_default_provider_t { - - /** - * public functions - */ - xauth_provider_t public; -}; - -METHOD(xauth_provider_t, get_secret, bool, - private_xauth_default_provider_t *this, connection_t *c, chunk_t *secret) -{ - identification_t *user, *server; - - server = c->spd.that.id; - user = (c->xauth_identity) ? c->xauth_identity : c->spd.this.id; - - return get_xauth_secret(user, server, secret); -} - -METHOD(xauth_provider_t, destroy, void, - private_xauth_default_provider_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -xauth_provider_t *xauth_default_provider_create() -{ - private_xauth_default_provider_t *this; - - INIT(this, - .public = { - .get_secret = _get_secret, - .destroy = _destroy, - } - ); - - return &this->public; -} - diff --git a/src/pluto/plugins/xauth/xauth_default_provider.h b/src/pluto/plugins/xauth/xauth_default_provider.h deleted file mode 100644 index ff1a91d16..000000000 --- a/src/pluto/plugins/xauth/xauth_default_provider.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_default_provider xauth_default_provider - * @{ @ingroup xauth - */ - -#ifndef XAUTH_DEFAULT_PROVIDER_H_ -#define XAUTH_DEFAULT_PROVIDER_H_ - -#include - - -/** - * Create an xauth_default_provider instance. - */ -xauth_provider_t *xauth_default_provider_create(); - -#endif /** XAUTH_DEFAULT_PROVIDER_H_ @}*/ - diff --git a/src/pluto/plugins/xauth/xauth_default_verifier.c b/src/pluto/plugins/xauth/xauth_default_verifier.c deleted file mode 100644 index ca2e36aa0..000000000 --- a/src/pluto/plugins/xauth/xauth_default_verifier.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "xauth_default_verifier.h" - -typedef struct private_xauth_default_verifier_t private_xauth_default_verifier_t; - -/** - * private data of xauth_default_verifier - */ -struct private_xauth_default_verifier_t { - - /** - * public functions - */ - xauth_verifier_t public; -}; - -METHOD(xauth_verifier_t, verify_secret, bool, - private_xauth_default_verifier_t *this, connection_t *c, chunk_t secret) -{ - identification_t *user, *server; - chunk_t xauth_secret; - bool success = FALSE; - - server = c->spd.this.id; - user = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - if (get_xauth_secret(user, server, &xauth_secret)) - { - success = chunk_equals(secret, xauth_secret); - - if (!success && secret.len && secret.ptr[secret.len - 1] == 0) - { /* fix for null-terminated passwords (e.g. from Android 4) */ - secret.len--; - success = chunk_equals(secret, xauth_secret); - } - - chunk_clear(&xauth_secret); - } - return success; -} - -METHOD(xauth_verifier_t, destroy, void, - private_xauth_default_verifier_t *this) -{ - free(this); -} - - -/* - * Described in header. - */ -xauth_verifier_t *xauth_default_verifier_create() -{ - private_xauth_default_verifier_t *this; - - INIT(this, - .public = { - .verify_secret = _verify_secret, - .destroy = _destroy, - } - ); - - return &this->public; -} - diff --git a/src/pluto/plugins/xauth/xauth_default_verifier.h b/src/pluto/plugins/xauth/xauth_default_verifier.h deleted file mode 100644 index e5814d7b4..000000000 --- a/src/pluto/plugins/xauth/xauth_default_verifier.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_default_verifier xauth_default_verifier - * @{ @ingroup xauth - */ - -#ifndef XAUTH_DEFAULT_VERIFIER_H_ -#define XAUTH_DEFAULT_VERIFIER_H_ - -#include - - -/** - * Create an xauth_default_verifier instance. - */ -xauth_verifier_t *xauth_default_verifier_create(); - -#endif /** XAUTH_DEFAULT_VERIFIER_H_ @}*/ - diff --git a/src/pluto/plugins/xauth/xauth_plugin.c b/src/pluto/plugins/xauth/xauth_plugin.c deleted file mode 100644 index bfc4820ed..000000000 --- a/src/pluto/plugins/xauth/xauth_plugin.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "xauth_plugin.h" -#include "xauth_default_provider.h" -#include "xauth_default_verifier.h" - -METHOD(plugin_t, get_name, char*, - xauth_plugin_t *this) -{ - return "xauth"; -} - -METHOD(plugin_t, destroy, void, - xauth_plugin_t *this) -{ - free(this); -} - -/* - * see header file - */ -plugin_t *xauth_plugin_create() -{ - xauth_plugin_t *this; - - INIT(this, - .plugin = { - .get_name = _get_name, - .reload = (void*)return_false, - .destroy = _destroy, - }, - ); - - pluto->xauth->add_provider(pluto->xauth, xauth_default_provider_create()); - pluto->xauth->add_verifier(pluto->xauth, xauth_default_verifier_create()); - - return &this->plugin; -} - diff --git a/src/pluto/plugins/xauth/xauth_plugin.h b/src/pluto/plugins/xauth/xauth_plugin.h deleted file mode 100644 index 4f14828d2..000000000 --- a/src/pluto/plugins/xauth/xauth_plugin.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth xauth - * @ingroup pplugins - * - * @defgroup xauth_plugin xauth_plugin - * @{ @ingroup xauth - */ - -#ifndef XAUTH_PLUGIN_H_ -#define XAUTH_PLUGIN_H_ - -#include - -typedef struct xauth_plugin_t xauth_plugin_t; - -/** - * XAUTH plugin - */ -struct xauth_plugin_t { - - /** - * implements plugin interface - */ - plugin_t plugin; -}; - -#endif /** XAUTH_PLUGIN_H_ @}*/ diff --git a/src/pluto/pluto.8 b/src/pluto/pluto.8 deleted file mode 100644 index ed6f78050..000000000 --- a/src/pluto/pluto.8 +++ /dev/null @@ -1,1594 +0,0 @@ -.TH IPSEC_PLUTO 8 "28 March 1999" -.SH NAME -pluto \- IPsec IKE keying daemon and control interface -.PP -whack \- control interface for IKE keying daemon -.SH SYNOPSIS -.na -.nh -.HP -.ft B -ipsec pluto -[\-\-help] -[\-\-version] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-nofork] -[\-\-stderrlog] -[\-\-uniqueids] -[\fB\-\-interface\fP \fIinterfacename\fP] -[\-\-ikeport\ \c -\fIportnumber\fP] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-secretsfile\ \c -\fIsecrets\(hyfile\fP] -[\-\-adns \fIpathname\fP] -[\-\-lwdnsq \fIpathname\fP] -[\-\-perpeerlog] -[\-\-perpeerlogbase\ \c -\fIdirname\fP] -[\-\-debug\(hynone] -[\-\-debug\(hyall] -[\-\-debug\(hyraw] -[\-\-debug\(hycrypt] -[\-\-debug\(hyparsing] -[\-\-debug\(hyemitting] -[\-\-debug\(hycontrol] -[\-\-debug\(hylifecycle] -[\-\-debug\(hykernel] -[\-\-debug\(hydns] -[\-\-debug\(hyoppo] -[\-\-debug\(hyprivate] -.HP -.ft B -ipsec whack -[\-\-help] -[\-\-version] -.HP -.ft B -ipsec whack -\-\-name\ \c -\fIconnection-name\fP -.br -[\-\-id\ \c -\fIid\fP] \c -[\-\-host\ \c -\fIip\(hyaddress\fP] -[\-\-ikeport\ \c -\fIport\(hynumber\fP] -[\-\-nexthop\ \c -\fIip\(hyaddress\fP] -[\-\-client\ \c -\fIsubnet\fP] -[\-\-dnskeyondemand] -[\-\-updown\ \c -\fIupdown\fP] -.br -\-\-to -.br -[\-\-id\ \c -\fIid\fP] -[\-\-host\ \c -\fIip\(hyaddress\fP] -[\-\-ikeport\ \c -\fIport\(hynumber\fP] -[\-\-nexthop\ \c -\fIip\(hyaddress\fP] -[\-\-client\ \c -\fIsubnet\fP] -[\-\-dnskeyondemand] -[\-\-updown\ \c -\fIupdown\fP] -.br -[\-\-psk] -[\-\-rsasig] -[\-\-encrypt] -[\-\-authenticate] -[\-\-compress] -[\-\-tunnel] -[\-\-pfs] -[\-\-disablearrivalcheck] -[\-\-ipv4] -[\-\-ipv6] -[\-\-tunnelipv4] -[\-\-tunnelipv6] -[\-\-ikelifetime\ \c -\fIseconds\fP] -[\-\-ipseclifetime\ \c -\fIseconds\fP] -[\-\-rekeymargin\ \c -\fIseconds\fP] -[\-\-rekeyfuzz\ \c -\fIpercentage\fP] -[\-\-keyingtries\ \c -\fIcount\fP] -[\-\-dontrekey] -[\-\-delete] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-keyid\ \c -\fIid\fP -[\-\-addkey] -[\-\-pubkeyrsa\ \c -\fIkey\fP] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-myid\ \c -\fIid\fP -.HP -.ft B -ipsec whack -\-\-listen|\-\-unlisten -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-route|\-\-unroute -\-\-name\ \c -\fIconnection-name\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-initiate|\-\-terminate -\-\-name\ \c -\fIconnection-name\fP -[\-\-asynchronous] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -[\-\-tunnelipv4] -[\-\-tunnelipv6] -\-\-oppohere \fIip\(hyaddress\fP -\-\-oppothere \fIip\(hyaddress\fP -.HP -.ft B -ipsec whack -\-\-delete -\-\-name\ \c -\fIconnection-name\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-deletestate\ \c -\fIstate-number\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -[\-\-name\ \c -\fIconnection-name\fP] -[\-\-debug\(hynone] -[\-\-debug\(hyall] -[\-\-debug\(hyraw] -[\-\-debug\(hycrypt] -[\-\-debug\(hyparsing] -[\-\-debug\(hyemitting] -[\-\-debug\(hycontrol] -[\-\-debug\(hylifecycle] -[\-\-debug\(hykernel] -[\-\-debug\(hydns] -[\-\-debug\(hyoppo] -[\-\-debug\(hyprivate] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-status -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-shutdown -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.ft R -.hy -.ad -.SH DESCRIPTION -.BR pluto -is an IKE (``IPsec Key Exchange'') daemon. -.BR whack -is an auxiliary program to allow requests to be made to a running -.BR pluto . -.LP -.BR pluto -is used to automatically build shared ``security associations'' on a -system that has IPsec, the secure IP protocol. -In other words, -.BR pluto -can eliminate much of the work of manual keying. -The actual -secure transmission of packets is the responsibility of the Linux kernel. -\fIipsec_auto\fP(8) provides a more convenient interface to -\fBpluto\fP and \fBwhack\fP. -.SS IKE's Job -.LP -A \fISecurity Association\fP (\fISA\fP) is an agreement between two network nodes on -how to process certain traffic between them. This processing involves -encapsulation, authentication, encryption, or compression. -.LP -IKE can be deployed on a network node to negotiate Security -Associations for that node. These IKE implementations can only -negotiate with other IKE implementations, so IKE must be on each node -that is to be an endpoint of an IKE-negotiated Security Association. -No other nodes need to be running IKE. -.LP -An IKE instance (i.e. an IKE implementation on a particular network -node) communicates with another IKE instance using UDP IP packets, so -there must be a route between the nodes in each direction. -.LP -The negotiation of Security Associations requires a number of choices -that involve tradeoffs between security, convenience, trust, and -efficiency. These are policy issues and are normally specified to the -IKE instance by the system administrator. -.LP -IKE deals with two kinds of Security Associations. The first part of -a negotiation between IKE instances is to build an ISAKMP SA. An -ISAKMP SA is used to protect communication between the two IKEs. -IPsec SAs can then be built by the IKEs \- these are used to carry -protected IP traffic between the systems. -.LP -The negotiation of the ISAKMP SA is known as Phase 1. In theory, -Phase 1 can be accomplished by a couple of different exchange types, -but we only implement one called Main Mode (we don't implement -Aggressive Mode). -.LP -Any negotiation under the protection of an ISAKMP SA, including the -negotiation of IPsec SAs, is part of Phase 2. The exchange type -that we use to negotiate an IPsec SA is called Quick Mode. -.LP -IKE instances must be able to authenticate each other as part of their -negotiation of an ISAKMP SA. This can be done by several mechanisms -described in the draft standards. -.LP -IKE negotiation can be initiated by any instance with any other. If -both can find an agreeable set of characteristics for a Security -Association, and both recognize each others authenticity, they can set -up a Security Association. The standards do not specify what causes -an IKE instance to initiate a negotiation. -.LP -In summary, an IKE instance is prepared to automate the management of -Security Associations in an IPsec environment, but a number of issues -are considered policy and are left in the system administrator's hands. -.SS Pluto -.LP -\fBpluto\fP is an implementation of IKE. It runs as a daemon on a network -node. Currently, this network node must be a Linux 2.6 system running the -native \fBNETKEY\fP IPsec stack. -.LP -\fBpluto\fP only implements a subset of IKE. This is enough for it to -interoperate with other instances of \fBpluto\fP, and many other IKE -implementations. We are working on implementing more of IKE. -.LP -The policy for acceptable characteristics for Security Associations is -mostly hardwired into the code of \fBpluto\fP (spdb.c). Eventually -this will be moved into a security policy database with reasonable -expressive power and more convenience. -.LP -\fBpluto\fP uses shared secrets or RSA signatures to authenticate -peers with whom it is negotiating. -.LP -\fBpluto\fP initiates negotiation of a Security Association when it is -manually prodded: the program \fBwhack\fP is run to trigger this. -It will also initiate a negotiation when the Linux kernel traps an outbound -packet for Opportunistic Encryption. -.LP -\fBpluto\fP implements ISAKMP SAs itself. After it has negotiated the -characteristics of an IPsec SA, it directs the Linux kernel to implement it. -It also invokes a script to adjust any firewall and issue \fIroute\fP(8) -commands. -.LP -When \fBpluto\fP shuts down, it closes all Security Associations. -.SS Before Running Pluto -.LP -\fBpluto\fP runs as a daemon with userid root. Before running it, a few -things must be set up. -.LP -\fBpluto\fP requires a Linux 2.6 kernel with the modules for the native IPsec -stack enabled. -.LP -\fBpluto\fP supports multiple public networks (that is, networks -that are considered insecure and thus need to have their traffic -encrypted or authenticated). It discovers the -public interfaces to use by looking at all interfaces that are -configured (the \fB\-\-interface\fP option can be used to limit -the interfaces considered). -It does this only when \fBwhack\fP tells it to \-\-listen, -so the interfaces must be configured by then. -\fIifconfig\fP(8) with the \fB\-a\fP flag will show -the name and status of each network interface. -.LP -\fBpluto\fP requires a database of preshared secrets and RSA private keys. -This is described in the -.IR ipsec.secrets (5). -\fBpluto\fP is told of RSA public keys via \fBwhack\fP commands. -If the connection is Opportunistic, and no RSA public key is known, -\fBpluto\fP will attempt to fetch RSA keys using the Domain Name System. -.SS ipsec.secrets file -.LP -A \fBpluto\fP daemon and another IKE daemon (for example, another instance -of \fBpluto\fP) must convince each other that they are who they are supposed -to be before any negotiation can succeed. This authentication is -accomplished by using either secrets that have been shared beforehand -(manually) or by using RSA signatures. There are other techniques, -but they have not been implemented in \fBpluto\fP. -.LP -The file \fI/etc/ipsec.secrets\fP is used to keep preshared secret keys -and RSA private keys for -authentication with other IKE daemons. For debugging, there is an -argument to the \fBpluto\fP command to use a different file. -This file is described in -.IR ipsec.secrets (5). -.SS Running Pluto -.LP -To fire up the daemon, just type \fBpluto\fP (be sure to be running as -the superuser). -The default IKE port number is 500, the UDP port assigned by IANA for IKE Daemons. -\fBpluto\fP must be run by the superuser to be able to use the UDP 500 port. -.LP -\fBpluto\fP attempts to create a lockfile with the name -\fI/var/run/pluto.pid\fP. If the lockfile cannot be created, -\fBpluto\fP exits \- this prevents multiple \fBpluto\fPs from -competing Any ``leftover'' lockfile must be removed before -\fBpluto\fP will run. \fBpluto\fP writes its pid into this file so -that scripts can find it. This lock will not function properly if it -is on an NFS volume (but sharing locks on multiple machines doesn't -make sense anyway). -.LP -\fBpluto\fP then forks and the parent exits. This is the conventional -``daemon fork''. It can make debugging awkward, so there is an option -to suppress this fork. -.LP -All logging, including diagnostics, is sent to -.IR syslog (3) -with facility=authpriv; -it decides where to put these messages (possibly in /var/log/secure). -Since this too can make debugging awkward, there is an option to -steer logging to stderr. -.LP -If the \fB\-\-perpeerlog\fP option is given, then pluto will open -a log file per connection. By default, this is in /var/log/pluto/peer, -in a subdirectory formed by turning all dot (.) [IPv4} or colon (:) -[IPv6] into slashes (/). -.LP -The base directory can be changed with the \fB\-\-perpeerlogbase\fP. -.LP -Once \fBpluto\fP is started, it waits for requests from \fBwhack\fP. -.SS Pluto's Internal State -.LP -To understand how to use \fBpluto\fP, it is helpful to understand a little -about its internal state. Furthermore, the terminology is needed to decipher -some of the diagnostic messages. -.LP -The \fI(potential) connection\fP database describes attributes of a -connection. These include the IP addresses of the hosts and client -subnets and the security characteristics desired. \fBpluto\fP -requires this information (simply called a connection) before it can -respond to a request to build an SA. Each connection is given a name -when it is created, and all references are made using this name. -.LP -During the IKE exchange to build an SA, the information about the -negotiation is represented in a \fIstate object\fP. Each state object -reflects how far the negotiation has reached. Once the negotiation is -complete and the SA established, the state object remains to represent -the SA. When the SA is terminated, the state object is discarded. -Each State object is given a serial number and this is used to refer -to the state objects in logged messages. -.LP -Each state object corresponds to a connection and can be thought of -as an instantiation of that connection. -At any particular time, there may be any number of state objects -corresponding to a particular connection. -Often there is one representing an ISAKMP SA and another representing -an IPsec SA. -.LP -Each connection may be routed, and must be while it has an IPsec SA. -The connection specifies the characteristics of the route: the -interface on this machine, the ``gateway'' (the nexthop), -and the peer's client subnet. Two -connections may not be simultaneously routed if they are for the same -peer's client subnet but use different interfaces or gateways -(\fBpluto\fP's logic does not reflect any advanced routing capabilities). -.LP -Each eroute is associated with the state object for an IPsec SA -because it has the particular characteristics of the SA. -Two eroutes conflict if they specify the identical local -and remote clients (unlike for routes, the local clients are -taken into account). -.LP -When \fBpluto\fP needs to install a route for a connection, -it must make sure that no conflicting route is in use. If another -connection has a conflicting route, that route will be taken down, as long -as there is no IPsec SA instantiating that connection. -If there is such an IPsec SA, the attempt to install a route will fail. -.LP -There is an exception. If \fBpluto\fP, as Responder, needs to install -a route to a fixed client subnet for a connection, and there is -already a conflicting route, then the SAs using the route are deleted -to make room for the new SAs. The rationale is that the new -connection is probably more current. The need for this usually is a -product of Road Warrior connections (these are explained later; they -cannot be used to initiate). -.LP -When \fBpluto\fP needs to install an eroute for an IPsec SA (for a -state object), first the state object's connection must be routed (if -this cannot be done, the eroute and SA will not be installed). -If a conflicting eroute is already in place for another connection, -the eroute and SA will not be installed (but note that the routing -exception mentioned above may have already deleted potentially conflicting SAs). -If another IPsec -SA for the same connection already has an eroute, all its outgoing traffic -is taken over by the new eroute. The incoming traffic will still be -processed. This characteristic is exploited during rekeying. -.LP -Some of these routing characteristics are specific to \fBKLIPS\fP, the FreeS/WAN -implementation of IPsec and are not relevant when running pluto on the native -Linux 2.6 IPsec stack. -.SS Using Whack -.LP -\fBwhack\fP is used to command a running \fBpluto\fP. -\fBwhack\fP uses a UNIX domain socket to speak to \fBpluto\fP -(by default, \fI/var/pluto.ctl\fP). -.LP -\fBwhack\fP has an intricate argument syntax. -This syntax allows many different functions to be specified. -The help form shows the usage or version information. -The connection form gives \fBpluto\fP a description of a potential connection. -The public key form informs \fBpluto\fP of the RSA public key for a potential peer. -The delete form deletes a connection description and all SAs corresponding -to it. -The listen form tells \fBpluto\fP to start or stop listening on the public interfaces -for IKE requests from peers. -The route form tells \fBpluto\fP to set up routing for a connection; -the unroute form undoes this. -The initiate form tells \fBpluto\fP to negotiate an SA corresponding to a connection. -The terminate form tells \fBpluto\fP to remove all SAs corresponding to a connection, -including those being negotiated. -The status form displays the \fBpluto\fP's internal state. -The debug form tells \fBpluto\fP to change the selection of debugging output -``on the fly''. The shutdown form tells -\fBpluto\fP to shut down, deleting all SAs. -.LP -Most options are specific to one of the forms, and will be described -with that form. There are three options that apply to all forms. -.TP -\fB\-\-ctlbase\fP\ \fIpath\fP -\fIpath\fP.ctl is used as the UNIX domain socket for talking -to \fBpluto\fP. -This option facilitates debugging. -.TP -\fB\-\-optionsfrom\fP\ \fIfilename\fP -adds the contents of the file to the argument list. -.TP -\fB\-\-label\fP\ \fIstring\fP -adds the string to all error messages generated by \fBwhack\fP. -.LP -The help form of \fBwhack\fP is self-explanatory. -.TP -\fB\-\-help\fP -display the usage message. -.TP -\fB\-\-version\fP -display the version of \fBwhack\fP. -.LP -The connection form describes a potential connection to \fBpluto\fP. -\fBpluto\fP needs to know what connections can and should be negotiated. -When \fBpluto\fP is the initiator, it needs to know what to propose. -When \fBpluto\fP is the responder, it needs to know enough to decide whether -is is willing to set up the proposed connection. -.LP -The description of a potential connection can specify a large number -of details. Each connection has a unique name. This name will appear -in a updown shell command, so it should not contain punctuation -that would make the command ill-formed. -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The topology of -a connection is symmetric, so to save space here is half a picture: - -\ \ \ client_subnet<\-\->host:ikeport<\-\->nexthop<\-\-\- - -A similar trick is used in the flags. The same flag names are used for -both ends. Those before the \fB\-\-to\fP flag describe the left side -and those afterwards describe the right side. When \fBpluto\fP attempts -to use the connection, it decides whether it is the left side or the right -side of the connection, based on the IP numbers of its interfaces. -.TP -\fB\-\-id\fP\ \fIid\fP -the identity of the end. Currently, this can be an IP address (specified -as dotted quad or as a Fully Qualified Domain Name, which will be resolved -immediately) or as a Fully Qualified Domain Name itself (prefixed by ``@'' -to signify that it should not be resolved), or as user@FQDN, or as the -magic value \fB%myid\fP. -\fBPluto\fP only authenticates the identity, and does not use it for -addressing, so, for example, an IP address need not be the one to which -packets are to be sent. If the option is absent, the -identity defaults to the IP address specified by \fB\-\-host\fP. -\fB%myid\fP allows the identity to be separately specified (by the \fBpluto\fP or \fBwhack\fP option \fB\-\-myid\fP -or by the \fBipsec.conf\fP(5) \fBconfig setup\fP parameter \fPmyid\fP). -Otherwise, \fBpluto\fP tries to guess what \fB%myid\fP should stand for: -the IP address of \fB%defaultroute\fP, if it is supported by a suitable TXT record in the reverse domain for that IP address, -or the system's hostname, if it is supported by a suitable TXT record in its forward domain. -.\" The identity is transmitted in the IKE protocol, and is what is authenticated. -.TP -\fB\-\-host\fP\ \fIip\(hyaddress\fP -.TP -\fB\-\-host\fP\ \fB%any\fP -.TP -\fB\-\-host\fP\ \fB%opportunistic\fP -the IP address of the end (generally the public interface). -If \fBpluto\fP is to act as a responder -for IKE negotiations initiated from unknown IP addresses (the -``Road Warrior'' case), the -IP address should be specified as \fB%any\fP (currently, -the obsolete notation \fB0.0.0.0\fP is also accepted for this). -If \fBpluto\fP is to opportunistically initiate the connection, -use \fB%opportunistic\fP -.TP -\fB\-\-ikeport\fP\ \fIport\(hynumber\fP -the UDP port that IKE listens to on that host. The default is 500. -(\fBpluto\fP on this machine uses the port specified by its own command -line argument, so this only affects where \fBpluto\fP sends messages.) -.TP -\fB\-\-nexthop\fP\ \fIip\(hyaddress\fP -where to route packets for the peer's client (presumably for the peer too, -but it will not be used for this). -When \fBpluto\fP installs an IPsec SA, it issues a route command. -It uses the nexthop as the gateway. -The default is the peer's IP address (this can be explicitly written as -\fB%direct\fP; the obsolete notation \fB0.0.0.0\fP is accepted). -This option is necessary if \fBpluto\fP's host's interface used for sending -packets to the peer is neither point-to-point nor directly connected to the -peer. -.TP -\fB\-\-client\fP\ \fIsubnet\fP -the subnet for which the IPsec traffic will be destined. If not specified, -the host will be the client. -The subnet can be specified in any of the forms supported by \fIipsec_atosubnet\fP(3). -The general form is \fIaddress\fP/\fImask\fP. The \fIaddress\fP can be either -a domain name or four decimal numbers (specifying octets) separated by dots. -The most convenient form of the \fImask\fP is a decimal integer, specifying -the number of leading one bits in the mask. So, for example, 10.0.0.0/8 -would specify the class A network ``Net 10''. -.TP -\fB\-\-dnskeyondemand]\fP -specifies that when an RSA public key is needed to authenticate this -host, and it isn't already known, fetch it from DNS. -.TP -\fB\-\-updown\fP\ \fIupdown\fP -specifies an external shell command to be run whenever \fBpluto\fP -brings up or down a connection. -The script is used to build a shell command, so it may contain positional -parameters, but ought not to have punctuation that would cause the -resulting command to be ill-formed. -The default is \fIipsec _updown\fP. -.TP -\fB\-\-to\fP -separates the specification of the left and right ends of the connection. -.LP -The potential connection description also specifies characteristics of -rekeying and security. -.TP -\fB\-\-psk\fP -Propose and allow preshared secret authentication for IKE peers. This authentication -requires that each side use the same secret. May be combined with \fB\-\-rsasig\fP; -at least one must be specified. -.TP -\fB\-\-rsasig\fP -Propose and allow RSA signatures for authentication of IKE peers. This authentication -requires that each side have have a private key of its own and know the -public key of its peer. May be combined with \fB\-\-psk\fP; -at least one must be specified. -.TP -\fB\-\-encrypt\fP -All proposed or accepted IPsec SAs will include non-null ESP. -The actual choices of transforms are wired into \fBpluto\fP. -.TP -\fB\-\-authenticate\fP -All proposed IPsec SAs will include AH. -All accepted IPsec SAs will include AH or ESP with authentication. -The actual choices of transforms are wired into \fBpluto\fP. -Note that this has nothing to do with IKE authentication. -.TP -\fB\-\-compress\fP -All proposed IPsec SAs will include IPCOMP (compression). -This will be ignored if the kernel is not configured with IPCOMP support. -.TP -\fB\-\-tunnel\fP -the IPsec SA should use tunneling. Implicit if the SA is for clients. -Must only be used with \fB\-\-authenticate\fP or \fB\-\-encrypt\fP. -.TP -\fB\-\-ipv4\fP -The host addresses will be interpreted as IPv4 addresses. This is the -default. Note that for a connection, all host addresses must be of -the same Address Family (IPv4 and IPv6 use different Address Families). -.TP -\fB\-\-ipv6\fP -The host addresses (including nexthop) will be interpreted as IPv6 addresses. -Note that for a connection, all host addresses must be of -the same Address Family (IPv4 and IPv6 use different Address Families). -.TP -\fB\-\-tunnelipv4\fP -The client addresses will be interpreted as IPv4 addresses. The default is -to match what the host will be. This does not imply \fB\-\-tunnel\fP so the -flag can be safely used when no tunnel is actually specified. -Note that for a connection, all tunnel addresses must be of the same -Address Family. -.TP -\fB\-\-tunnelipv6\fP -The client addresses will be interpreted as IPv6 addresses. The default is -to match what the host will be. This does not imply \fB\-\-tunnel\fP so the -flag can be safely used when no tunnel is actually specified. -Note that for a connection, all tunnel addresses must be of the same -Address Family. -.TP -\fB\-\-pfs\fP -There should be Perfect Forward Secrecy \- new keying material will -be generated for each IPsec SA rather than being derived from the ISAKMP -SA keying material. -Since the group to be used cannot be negotiated (a dubious feature of the -standard), \fBpluto\fP will propose the same group that was used during Phase 1. -We don't implement a stronger form of PFS which would require that the -ISAKMP SA be deleted after the IPSEC SA is negotiated. -.TP -\fB\-\-disablearrivalcheck\fP -If the connection is a tunnel, allow packets arriving through the tunnel -to have any source and destination addresses. -.LP -If none of the \fB\-\-encrypt\fP, \fB\-\-authenticate\fP, \fB\-\-compress\fP, -or \fB\-\-pfs\fP flags is given, the initiating the connection will -only build an ISAKMP SA. For such a connection, client subnets have -no meaning and must not be specified. -.LP -More work is needed to allow for flexible policies. Currently -policy is hardwired in the source file spdb.c. The ISAKMP SAs may use -Oakley groups MODP1024 and MODP1536; 3DES encryption; SHA1-96 -and MD5-96 authentication. The IPsec SAs may use 3DES and -MD5-96 or SHA1-96 for ESP, or just MD5-96 or SHA1-96 for AH. -IPCOMP Compression is always Deflate. -.TP -\fB\-\-ikelifetime\fP\ \fIseconds\fP -how long \fBpluto\fP will propose that an ISAKMP SA be allowed to live. -The default is 10800 (three hours) and the maximum is 86400 (one day). -This option will not affect what is accepted. -\fBpluto\fP will reject proposals that exceed the maximum. -.TP -\fB\-\-ipseclifetime\fP\ \fIseconds\fP -how long \fBpluto\fP will propose that an IPsec SA be allowed to live. -The default is 3600 (one hour) and the maximum is 86400 (one day). -This option will not affect what is accepted. -\fBpluto\fP will reject proposals that exceed the maximum. -.TP -\fB\-\-rekeymargin\fP\ \fIseconds\fP -how long before an SA's expiration should \fBpluto\fP try to negotiate -a replacement SA. This will only happen if \fBpluto\fP was the initiator. -The default is 540 (nine minutes). -.TP -\fB\-\-rekeyfuzz\fP\ \fIpercentage\fP -maximum size of random component to add to rekeymargin, expressed as -a percentage of rekeymargin. \fBpluto\fP will select a delay uniformly -distributed within this range. By default, the percentage will be 100. -If greater determinism is desired, specify 0. It may be appropriate -for the percentage to be much larger than 100. -.TP -\fB\-\-keyingtries\fP\ \fIcount\fP -how many times \fBpluto\fP should try to negotiate an SA, -either for the first time or for rekeying. -A value of 0 is interpreted as a very large number: never give up. -The default is three. -.TP -\fB\-\-dontrekey\fP -A misnomer. -Only rekey a connection if we were the Initiator and there was recent -traffic on the existing connection. -This applies to Phase 1 and Phase 2. -This is currently the only automatic way for a connection to terminate. -It may be useful with Road Warrior or Opportunistic connections. -.br -Since SA lifetime negotiation is take-it-or-leave it, a Responder -normally uses the shorter of the negotiated or the configured lifetime. -This only works because if the lifetime is shorter than negotiated, -the Responder will rekey in time so that everything works. -This interacts badly with \fB\-\-dontrekey\fP. In this case, -the Responder will end up rekeying to rectify a shortfall in an IPsec SA -lifetime; for an ISAKMP SA, the Responder will accept the negotiated -lifetime. -.TP -\fB\-\-delete\fP -when used in the connection form, it causes any previous connection -with this name to be deleted before this one is added. Unlike a -normal delete, no diagnostic is produced if there was no previous -connection to delete. Any routing in place for the connection is undone. -.LP -The delete form deletes a named connection description and any -SAs established or negotiations initiated using this connection. -Any routing in place for the connection is undone. -.TP -\fB\-\-delete\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The deletestate form deletes the state object with the specified serial number. -This is useful for selectively deleting instances of connections. -.TP -\fB\-\-deletestate\fP\ \fIstate-number\fP -.LP -The route form of the \fBwhack\fP command tells \fBpluto\fP to set up -routing for a connection. -Although like a traditional route, it uses an ipsec device as a -virtual interface. -Once routing is set up, no packets will be -sent ``in the clear'' to the peer's client specified in the connection. -A TRAP shunt eroute will be installed; if outbound traffic is caught, -Pluto will initiate the connection. -An explicit \fBwhack\fP route is not always needed: if it hasn't been -done when an IPsec SA is being installed, one will be automatically attempted. -.LP -When a routing is attempted for a connection, there must not already -be a routing for a different connection with the same subnet but different -interface or destination, or if -there is, it must not be being used by an IPsec SA. Otherwise the -attempt will fail. -.TP -\fB\-\-route\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The unroute form of the \fBwhack\fP command tells \fBpluto\fP to undo -a routing. \fBpluto\fP will refuse if an IPsec SA is using the connection. -If another connection is sharing the same routing, it will be left in place. -Without a routing, packets will be sent without encryption or authentication. -.TP -\fB\-\-unroute\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The initiate form tells \fBpluto\fP to initiate a negotiation with another -\fBpluto\fP (or other IKE daemon) according to the named connection. -Initiation requires a route that \fB\-\-route\fP would provide; -if none is in place at the time an IPsec SA is being installed, -\fBpluto\fP attempts to set one up. -.TP -\fB\-\-initiate\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.TP -\fB\-\-asynchronous -.LP -The initiate form of the \fBwhack\fP command will relay back from -\fBpluto\fP status information via the UNIX domain socket (unless -\-\-asynchronous is specified). The status information is meant to -look a bit like that from \fBFTP\fP. Currently \fBwhack\fP simply -copies this to stderr. When the request is finished (eg. the SAs are -established or \fBpluto\fP gives up), \fBpluto\fP closes the channel, -causing \fBwhack\fP to terminate. -.LP -The opportunistic initiate form is mainly used for debugging. -.TP -\fB\-\-tunnelipv4\fP -.TP -\fB\-\-tunnelipv6\fP -.TP -\fB\-\-oppohere\fP\ \fIip-address\fP -.TP -\fB\-\-oppothere\fP\ \fIip-address\fP -.LP -This will cause \fBpluto\fP to attempt to opportunistically initiate a -connection from here to the there, even if a previous attempt -had been made. -The whack log will show the progress of this attempt. -.LP -The terminate form tells \fBpluto\fP to delete any SAs that use the specified -connection and to stop any negotiations in process. -It does not prevent new negotiations from starting (the delete form -has this effect). -.TP -\fB\-\-terminate\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The public key for informs \fBpluto\fP of the RSA public key for a potential peer. -Private keys must be kept secret, so they are kept in -.IR ipsec.secrets (5). -.TP -\fB\-\-keyid\ \fP\fIid\fP -specififies the identity of the peer for which a public key should be used. -Its form is identical to the identity in the connection. -If no public key is specified, \fBpluto\fP attempts to find KEY records -from DNS for the id (if a FQDN) or through reverse lookup (if an IP address). -Note that there several interesting ways in which this is not secure. -.TP -\fB\-\-addkey\fP -specifies that the new key is added to the collection; otherwise the -new key replaces any old ones. -.TP -\fB\-\-pubkeyrsa\ \fP\fIkey\fP -specifies the value of the RSA public key. It is a sequence of bytes -as described in RFC 2537 ``RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)''. -It is denoted in a way suitable for \fIipsec_ttodata\fP(3). -For example, a base 64 numeral starts with 0s. -.LP -The listen form tells \fBpluto\fP to start listening for IKE requests -on its public interfaces. To avoid race conditions, it is normal to -load the appropriate connections into \fBpluto\fP before allowing it -to listen. If \fBpluto\fP isn't listening, it is pointless to -initiate negotiations, so it will refuse requests to do so. Whenever -the listen form is used, \fBpluto\fP looks for public interfaces and -will notice when new ones have been added and when old ones have been -removed. This is also the trigger for \fBpluto\fP to read the -\fIipsec.secrets\fP file. So listen may useful more than once. -.TP -\fB\-\-listen\fP -start listening for IKE traffic on public interfaces. -.TP -\fB\-\-unlisten\fP -stop listening for IKE traffic on public interfaces. -.LP -The status form will display information about the internal state of -\fBpluto\fP: information about each potential connection, about -each state object, and about each shunt that \fBpluto\fP is managing -without an associated connection. -.TP -\fB\-\-status\fP -.LP -The shutdown form is the proper way to shut down \fBpluto\fP. -It will tear down the SAs on this machine that \fBpluto\fP has negotiated. -It does not inform its peers, so the SAs on their machines remain. -.TP -\fB\-\-shutdown\fP -.SS Examples -.LP -It would be normal to start \fBpluto\fP in one of the system initialization -scripts. It needs to be run by the superuser. Generally, no arguments are needed. -To run in manually, the superuser can simply type - -\ \ \ ipsec pluto - -The command will immediately return, but a \fBpluto\fP process will be left -running, waiting for requests from \fBwhack\fP or a peer. -.LP -Using \fBwhack\fP, several potential connections would be described: -.HP -.na -\ \ \ ipsec whack \-\-name\ silly -\-\-host\ 127.0.0.1 \-\-to \-\-host\ 127.0.0.2 -\-\-ikelifetime\ 900 \-\-ipseclifetime\ 800 \-\-keyingtries\ 3 -.ad -.LP -Since this silly connection description specifies neither encryption, -authentication, nor tunneling, it could only be used to establish -an ISAKMP SA. -.HP -.na -\ \ \ ipsec whack \-\-name\ secret \-\-host\ 10.0.0.1 \-\-client\ 10.0.1.0/24 -\-\-to \-\-host\ 10.0.0.2 \-\-client\ 10.0.2.0/24 -\-\-encrypt -.ad -.LP -This is something that must be done on both sides. If the other -side is \fBpluto\fP, the same \fBwhack\fP command could be used on it -(the command syntax is designed to not distinguish which end is ours). -.LP -Now that the connections are specified, \fBpluto\fP is ready to handle -requests and replies via the public interfaces. We must tell it to discover -those interfaces and start accepting messages from peers: - -\ \ \ ipsec whack \-\-listen -.LP -If we don't immediately wish to bring up a secure connection between -the two clients, we might wish to prevent insecure traffic. -The routing form asks \fBpluto\fP to cause the packets sent from -our client to the peer's client to be routed through the ipsec0 -device; if there is no SA, they will be discarded: - -\ \ \ ipsec whack \-\-route secret -.LP -Finally, we are ready to get \fBpluto\fP to initiate negotiation -for an IPsec SA (and implicitly, an ISAKMP SA): - -\ \ \ ipsec whack \-\-initiate\ \-\-name\ secret - -A small log of interesting events will appear on standard output -(other logging is sent to syslog). -.LP -\fBwhack\fP can also be used to terminate \fBpluto\fP cleanly, tearing down -all SAs that it has negotiated. - -\ \ \ ipsec whack \-\-shutdown - -Notification of any IPSEC SA deletion, but not ISAKMP SA deletion -is sent to the peer. Unfortunately, such Notification is not reliable. -Furthermore, \fBpluto\fP itself ignores Notifications. -.SS The updown command -.LP -Whenever \fBpluto\fP brings a connection up or down, it invokes -the updown command. This command is specified using the \fB\-\-updown\fP -option. This allows for customized control over routing and firewall manipulation. -.LP -The updown is invoked for five different operations. Each of -these operations can be for our client subnet or for our host itself. -.TP -\fBprepare-host\fP or \fBprepare-client\fP -is run before bringing up a new connection if no other connection -with the same clients is up. Generally, this is useful for deleting a -route that might have been set up before \fBpluto\fP was run or -perhaps by some agent not known to \fBpluto\fP. -.TP -\fBroute-host\fP or \fBroute-client\fP -is run when bringing up a connection for a new peer client subnet -(even if \fBprepare-host\fP or \fBprepare-client\fP was run). The -command should install a suitable route. Routing decisions are based -only on the destination (peer's client) subnet address, unlike eroutes -which discriminate based on source too. -.TP -\fBunroute-host\fP or \fBunroute-client\fP -is run when bringing down the last connection for a particular peer -client subnet. It should undo what the \fBroute-host\fP or \fBroute-client\fP -did. -.TP -\fBup-host\fP or \fBup-client\fP -is run when bringing up a tunnel eroute with a pair of client subnets -that does not already have a tunnel eroute. -This command should install firewall rules as appropriate. -It is generally a good idea to allow IKE messages (UDP port 500) -travel between the hosts. -.TP -\fBdown-host\fP or \fBdown-client\fP -is run when bringing down the eroute for a pair of client subnets. -This command should delete firewall rules as appropriate. Note that -there may remain some inbound IPsec SAs with these client subnets. -.LP -The script is passed a large number of environment variables to specify -what needs to be done. -.TP -\fBPLUTO_VERSION\fP -indicates what version of this interface is being used. This document -describes version 1.1. This is upwardly compatible with version 1.0. -.TP -\fBPLUTO_VERB\fP -specifies the name of the operation to be performed -(\fBprepare-host\fP,r \fBprepare-client\fP, -\fBup-host\fP, \fBup-client\fP, -\fBdown-host\fP, or \fBdown-client\fP). If the address family for -security gateway to security gateway communications is IPv6, then -a suffix of \-v6 is added to the verb. -.TP -\fBPLUTO_CONNECTION\fP -is the name of the connection for which we are routing. -.TP -\fBPLUTO_NEXT_HOP\fP -is the next hop to which packets bound for the peer must be sent. -.TP -\fBPLUTO_INTERFACE\fP -is the name of the ipsec interface to be used. -.TP -\fBPLUTO_ME\fP -is the IP address of our host. -.TP -\fBPLUTO_MY_CLIENT\fP -is the IP address / count of our client subnet. -If the client is just the host, this will be the host's own IP address / max -(where max is 32 for IPv4 and 128 for IPv6). -.TP -\fBPLUTO_MY_CLIENT_NET\fP -is the IP address of our client net. -If the client is just the host, this will be the host's own IP address. -.TP -\fBPLUTO_MY_CLIENT_MASK\fP -is the mask for our client net. -If the client is just the host, this will be 255.255.255.255. -.TP -\fBPLUTO_PEER\fP -is the IP address of our peer. -.TP -\fBPLUTO_PEER_CLIENT\fP -is the IP address / count of the peer's client subnet. -If the client is just the peer, this will be the peer's own IP address / max -(where max is 32 for IPv4 and 128 for IPv6). -.TP -\fBPLUTO_PEER_CLIENT_NET\fP -is the IP address of the peer's client net. -If the client is just the peer, this will be the peer's own IP address. -.TP -\fBPLUTO_PEER_CLIENT_MASK\fP -is the mask for the peer's client net. -If the client is just the peer, this will be 255.255.255.255. -.LP -All output sent by the script to stderr or stdout is logged. The -script should return an exit status of 0 if and only if it succeeds. -.LP -\fBPluto\fP waits for the script to finish and will not do any other -processing while it is waiting. -The script may assume that \fBpluto\fP will not change anything -while the script runs. -The script should avoid doing anything that takes much time and it -should not issue any command that requires processing by \fBpluto\fP. -Either of these activities could be performed by a background -subprocess of the script. -.SS Rekeying -.LP -When an SA that was initiated by \fBpluto\fP has only a bit of -lifetime left, -\fBpluto\fP will initiate the creation of a new SA. This applies to -ISAKMP and IPsec SAs. -The rekeying will be initiated when the SA's remaining lifetime is -less than the rekeymargin plus a random percentage, between 0 and -rekeyfuzz, of the rekeymargin. -.LP -Similarly, when an SA that was initiated by the peer has only a bit of -lifetime left, \fBpluto\fP will try to initiate the creation of a -replacement. -To give preference to the initiator, this rekeying will only be initiated -when the SA's remaining lifetime is half of rekeymargin. -If rekeying is done by the responder, the roles will be reversed: the -responder for the old SA will be the initiator for the replacement. -The former initiator might also initiate rekeying, so there may -be redundant SAs created. -To avoid these complications, make sure that rekeymargin is generous. -.LP -One risk of having the former responder initiate is that perhaps -none of its proposals is acceptable to the former initiator -(they have not been used in a successful negotiation). -To reduce the chances of this happening, and to prevent loss of security, -the policy settings are taken from the old SA (this is the case even if -the former initiator is initiating). -These may be stricter than those of the connection. -.LP -\fBpluto\fP will not rekey an SA if that SA is not the most recent of its -type (IPsec or ISAKMP) for its potential connection. -This avoids creating redundant SAs. -.LP -The random component in the rekeying time (rekeyfuzz) is intended to -make certain pathological patterns of rekeying unstable. If both -sides decide to rekey at the same time, twice as many SAs as necessary -are created. This could become a stable pattern without the -randomness. -.LP -Another more important case occurs when a security gateway has SAs -with many other security gateways. Each of these connections might -need to be rekeyed at the same time. This would cause a high peek -requirement for resources (network bandwidth, CPU time, entropy for -random numbers). The rekeyfuzz can be used to stagger the rekeying -times. -.LP -Once a new set of SAs has been negotiated, \fBpluto\fP will never send -traffic on a superseded one. Traffic will be accepted on an old SA -until it expires. -.SS Selecting a Connection When Responding: Road Warrior Support -.LP -When \fBpluto\fP receives an initial Main Mode message, it needs to -decide which connection this message is for. It picks based solely on -the source and destination IP addresses of the message. There might -be several connections with suitable IP addresses, in which case one -of them is arbitrarily chosen. (The ISAKMP SA proposal contained in -the message could be taken into account, but it is not.) -.LP -The ISAKMP SA is negotiated before the parties pass further -identifying information, so all ISAKMP SA characteristics specified in -the connection description should be the same for every connection -with the same two host IP addresses. At the moment, the only -characteristic that might differ is authentication method. -.LP -Up to this point, -all configuring has presumed that the IP addresses -are known to all parties ahead of time. This will not work -when either end is mobile (or assigned a dynamic IP address for other -reasons). We call this situation ``Road Warrior''. It is fairly tricky -and has some important limitations, most of which are features of -the IKE protocol. -.LP -Only the initiator may be mobile: -the initiator may have an IP number unknown to the responder. When -the responder doesn't recognize the IP address on the first Main Mode -packet, it looks for a connection with itself as one end and \fB%any\fP -as the other. -If it cannot find one, it refuses to negotiate. If it -does find one, it creates a temporary connection that is a duplicate -except with the \fB%any\fP replaced by the source IP address from the -packet; if there was no identity specified for the peer, the new IP -address will be used. -.LP -When \fBpluto\fP is using one of these temporary connections and -needs to find the preshared secret or RSA private key in \fIipsec.secrets\fP, -and and the connection specified no identity for the peer, \fB%any\fP -is used as its identity. After all, the real IP address was apparently -unknown to the configuration, so it is unreasonable to require that -it be used in this table. -.LP -Part way into the Phase 1 (Main Mode) negotiation using one of these -temporary connection descriptions, \fBpluto\fP will be receive an -Identity Payload. At this point, \fBpluto\fP checks for a more -appropriate connection, one with an identity for the peer that matches -the payload but which would use the same keys so-far used for -authentication. If it finds one, it will switch to using this better -connection (or a temporary derived from this, if it has \fB%any\fP -for the peer's IP address). It may even turn out that no connection -matches the newly discovered identity, including the current connection; -if so, \fBpluto\fP terminates negotiation. -.LP -Unfortunately, if preshared secret authentication is being used, the -Identity Payload is encrypted using this secret, so the secret must be -selected by the responder without knowing this payload. This -limits there to being at most one preshared secret for all Road Warrior -systems connecting to a host. RSA Signature authentications does not -require that the responder know how to select the initiator's public key -until after the initiator's Identity Payload is decoded (using the -responder's private key, so that must be preselected). -.LP -When \fBpluto\fP is responding to a Quick Mode negotiation via one of these -temporary connection descriptions, it may well find that the subnets -specified by the initiator don't match those in the temporary -connection description. If so, it will look for a connection with -matching subnets, its own host address, a peer address of \fB%any\fP -and matching identities. -If it finds one, a new temporary connection is derived from this one -and used for the Quick Mode negotiation of IPsec SAs. If it does not -find one, \fBpluto\fP terminates negotiation. -.LP -Be sure to specify an appropriate nexthop for the responder -to send a message to the initiator: \fBpluto\fP has no way of guessing -it (if forwarding isn't required, use an explicit \fB%direct\fP as the nexthop -and the IP address of the initiator will be filled in; the obsolete -notation \fB0.0.0.0\fP is still accepted). -.LP -\fBpluto\fP has no special provision for the initiator side. The current -(possibly dynamic) IP address and nexthop must be used in defining -connections. These must be -properly configured each time the initiator's IP address changes. -\fBpluto\fP has no mechanism to do this automatically. -.LP -Although we call this Road Warrior Support, it could also be used to -support encrypted connections with anonymous initiators. The -responder's organization could announce the preshared secret that would be used -with unrecognized initiators and let anyone connect. Of course the initiator's -identity would not be authenticated. -.LP -If any Road Warrior connections are supported, \fBpluto\fP cannot -reject an exchange initiated by an unknown host until it has -determined that the secret is not shared or the signature is invalid. -This must await the -third Main Mode message from the initiator. If no Road Warrior -connection is supported, the first message from an unknown source -would be rejected. This has implications for ease of debugging -configurations and for denial of service attacks. -.LP -Although a Road Warrior connection must be initiated by the mobile -side, the other side can and will rekey using the temporary connection -it has created. If the Road Warrior wishes to be able to disconnect, -it is probably wise to set \fB\-\-keyingtries\fP to 1 in the -connection on the non-mobile side to prevent it trying to rekey the -connection. Unfortunately, there is no mechanism to unroute the -connection automatically. -.SS Debugging -.LP -\fBpluto\fP accepts several optional arguments, useful mostly for debugging. -Except for \fB\-\-interface\fP, each should appear at most once. -.TP -\fB\-\-interface\fP \fIinterfacename\fP -specifies that the named real public network interface should be considered. -The interface name specified should not be \fBipsec\fP\fIN\fP. -If the option doesn't appear, all interfaces are considered. -To specify several interfaces, use the option once for each. -One use of this option is to specify which interface should be used -when two or more share the same IP address. -.TP -\fB\-\-ikeport\fP \fIport-number\fP -changes the UDP port that \fBpluto\fP will use -(default, specified by IANA: 500) -.TP -\fB\-\-ctlbase\fP \fIpath\fP -basename for control files. -\fIpath\fP.ctl is the socket through which \fBwhack\fP communicates with -\fBpluto\fP. -\fIpath\fP.pid is the lockfile to prevent multiple \fBpluto\fP instances. -The default is \fI/var/run/pluto\fP). -.TP -\fB\-\-secretsfile\fP \fIfile\fP -specifies the file for authentication secrets -(default: \fI/etc/ipsec.secrets\fP). -This name is subject to ``globbing'' as in \fIsh\fP(1), -so every file with a matching name is processed. -Quoting is generally needed to prevent the shell from doing the globbing. -.TP -\fB\-\-adns\fP \fIpathname\fP -.TP -\fB\-\-lwdnsq\fP \fIpathname\fP -specifies where to find \fBpluto\fP's helper program for asynchronous DNS lookup. -\fBpluto\fP can be built to use one of two helper programs: \fB_pluto_adns\fP -or \fBlwdnsq\fP. You must use the program for which it was built. -By default, \fBpluto\fP will look for the program in -\fB$IPSEC_DIR\fP (if that environment variable is defined) or, failing that, -in the same directory as \fBpluto\fP. -.TP -\fB\-\-nofork\fP -disable ``daemon fork'' (default is to fork). In addition, after the -lock file and control socket are created, print the line ``Pluto -initialized'' to standard out. -.TP -\fB\-\-uniqueids\fP -if this option has been selected, whenever a new ISAKMP SA is -established, any connection with the same Peer ID but a different -Peer IP address is unoriented (causing all its SAs to be deleted). -This helps clean up dangling SAs when a connection is lost and -then regained at another IP address. -.TP -\fB\-\-stderrlog\fP -log goes to standard out {default is to use \fIsyslogd\fP(8)) -.LP -\fBpluto\fP is willing to produce a prodigious amount of debugging -information. To do so, it must be compiled with \-DDEBUG. There are -several classes of debugging output, and \fBpluto\fP may be directed to -produce a selection of them. All lines of -debugging output are prefixed with ``|\ '' to distinguish them from error -messages. -.LP -When \fBpluto\fP is invoked, it may be given arguments to specify -which classes to output. The current options are: -.TP -\fB\-\-debug-raw\fP -show the raw bytes of messages -.TP -\fB\-\-debug-crypt\fP -show the encryption and decryption of messages -.TP -\fB\-\-debug-parsing\fP -show the structure of input messages -.TP -\fB\-\-debug-emitting\fP -show the structure of output messages -.TP -\fB\-\-debug-control\fP -show \fBpluto\fP's decision making -.TP -\fB\-\-debug-lifecycle\fP -[this option is temporary] log more detail of lifecycle of SAs -.TP -\fB\-\-debug-kernel\fP -show \fBpluto\fP's interaction with the kernel -.TP -\fB\-\-debug-dns\fP -show \fBpluto\fP's interaction with \fBDNS\fP for KEY and TXT records -.TP -\fB\-\-debug-oppo\fP -show why \fBpluto\fP didn't find a suitable DNS TXT record to authorize opportunistic initiation -.TP -\fB\-\-debug-all\fP -all of the above -.TP -\fB\-\-debug-private\fP -allow debugging output with private keys. -.TP -\fB\-\-debug-none\fP -none of the above -.LP -The debug form of the -\fBwhack\fP command will change the selection in a running -\fBpluto\fP. -If a connection name is specified, the flags are added whenever -\fBpluto\fP has identified that it is dealing with that connection. -Unfortunately, this is often part way into the operation being observed. -.LP -For example, to start a \fBpluto\fP with a display of the structure of input -and output: -.IP -pluto \-\-debug-emitting \-\-debug-parsing -.LP -To later change this \fBpluto\fP to only display raw bytes: -.IP -whack \-\-debug-raw -.LP -For testing, SSH's IKE test page is quite useful: -.IP -\fIhttp://isakmp-test.ssh.fi/\fP -.LP -Hint: ISAKMP SAs are often kept alive by IKEs even after the IPsec SA -is established. This allows future IPsec SA's to be negotiated -directly. If one of the IKEs is restarted, the other may try to use -the ISAKMP SA but the new IKE won't know about it. This can lead to -much confusion. \fBpluto\fP is not yet smart enough to get out of such a -mess. -.SS Pluto's Behaviour When Things Go Wrong -.LP -When \fBpluto\fP doesn't understand or accept a message, it just -ignores the message. It is not yet capable of communicating the -problem to the other IKE daemon (in the future it might use -Notifications to accomplish this in many cases). It does log a diagnostic. -.LP -When \fBpluto\fP gets no response from a message, it resends the same -message (a message will be sent at most three times). This is -appropriate: UDP is unreliable. -.LP -When pluto gets a message that it has already seen, there are many -cases when it notices and discards it. This too is appropriate for UDP. -.LP -Combine these three rules, and you can explain many apparently -mysterious behaviours. In a \fBpluto\fP log, retrying isn't usually the -interesting event. The critical thing is either earlier (\fBpluto\fP -got a message which it didn't like and so ignored, so it was still -awaiting an acceptable message and got impatient) or on the other -system (\fBpluto\fP didn't send a reply because it wasn't happy with -the previous message). -.SS Notes -.LP -Each IPsec SA is assigned an SPI, a 32-bit number used to refer to the SA. -The IKE protocol lets the destination of the SA choose the SPI. -The range 0 to 0xFF is reserved for IANA. -\fBPluto\fP also avoids choosing an SPI in the range 0x100 to 0xFFF, -leaving these SPIs free for manual keying. -Remember that the peer, if not \fBpluto\fP, may well chose -SPIs in this range. -.SS Policies -.LP -This catalogue of policies may be of use when trying to configure -\fBPluto\fP and another IKE implementation to interoperate. -.LP -In Phase 1, only Main Mode is supported. We are not sure that -Aggressive Mode is secure. For one thing, it does not support -identity protection. It may allow more severe Denial Of Service -attacks. -.LP -No Informational Exchanges are supported. These are optional and -since their delivery is not assured, they must not matter. -It is the case that some IKE implementations won't interoperate -without Informational Exchanges, but we feel they are broken. -.LP -No Informational Payloads are supported. These are optional, but -useful. It is of concern that these payloads are not authenticated in -Phase 1, nor in those Phase 2 messages authenticated with HASH(3). -.IP \(bu \w'\(bu\ 'u -Diffie Hellman Groups MODP 1024 and MODP 1536 (2 and 5) -are supported. -Group MODP768 (1) is not supported because it is too weak. -.IP \(bu -Host authetication can be done by RSA Signatures or Pre-Shared -Secrets. -.IP \(bu -3DES CBC (Cypher Block Chaining mode) is the only encryption -supported, both for ISAKMP SAs and IPSEC SAs. -.IP \(bu -MD5 and SHA1 hashing are supported for packet authentication in both -kinds of SAs. -.IP \(bu -The ESP, AH, or AH plus ESP are supported. If, and only if, AH and -ESP are combined, the ESP need not have its own authentication -component. The selection is controlled by the \-\-encrypt and -\-\-authenticate flags. -.IP \(bu -Each of these may be combined with IPCOMP Deflate compression, -but only if the potential connection specifies compression and only -if the kernel is configured with IPCOMP support. -.IP \(bu -The IPSEC SAs may be tunnel or transport mode, where appropriate. -The \-\-tunnel flag controls this when \fBpluto\fP is initiating. -.IP \(bu -When responding to an ISAKMP SA proposal, the maximum acceptable -lifetime is eight hours. The default is one hour. There is no -minimum. The \-\-ikelifetime flag controls this when \fBpluto\fP -is initiating. -.IP \(bu -When responding to an IPSEC SA proposal, the maximum acceptable -lifetime is one day. The default is eight hours. There is no -minimum. The \-\-ipseclifetime flag controls this when \fBpluto\fP -is initiating. -.IP \(bu -PFS is acceptable, and will be proposed if the \-\-pfs flag was -specified. The DH group proposed will be the same as negotiated for -Phase 1. -.SH SIGNALS -.LP -\fBPluto\fP responds to \fBSIGHUP\fP by issuing a suggestion that ``\fBwhack\fP -\-\-listen'' might have been intended. -.LP -\fBPluto\fP exits when it receives \fBSIGTERM\fP. -.SH EXIT STATUS -.LP -\fBpluto\fP normally forks a daemon process, so the exit status is -normally a very preliminary result. -.TP -0 -means that all is OK so far. -.TP -1 -means that something was wrong. -.TP -10 -means that the lock file already exists. -.LP -If \fBwhack\fP detects a problem, it will return an exit status of 1. -If it received progress messages from \fBpluto\fP, it returns as status -the value of the numeric prefix from the last such message -that was not a message sent to syslog or a comment -(but the prefix for success is treated as 0). -Otherwise, the exit status is 0. -.SH FILES -\fI/var/run/pluto.pid\fP -.br -\fI/var/run/pluto.ctl\fP -.br -\fI/etc/ipsec.secrets\fP -.br -\fI$IPSEC_LIBDIR/_pluto_adns\fP -.br -\fI$IPSEC_EXECDIR/lwdnsq\fP -.br -\fI/dev/urandom\fP -.SH ENVIRONMENT -\fIIPSEC_LIBDIR\fP -.br -\fIIPSEC_EXECDIR\fP -.br -\fIIPSECmyid\fP -.SH SEE ALSO -.LP -The rest of the FreeS/WAN distribution, in particular \fIipsec\fP(8). -.LP -\fIipsec_auto\fP(8) is designed to make using \fBpluto\fP more pleasant. -Use it! -.LP -.IR ipsec.secrets (5) -describes the format of the secrets file. -.LP -\fIipsec_atoaddr\fP(3), part of the FreeS/WAN distribution, describes the -forms that IP addresses may take. -\fIipsec_atosubnet\fP(3), part of the FreeS/WAN distribution, describes the -forms that subnet specifications. -.LP -For more information on IPsec, the mailing list, and the relevant -documents, see: -.IP -.nh -\fIhttp://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html\fP -.hy -.LP -At the time of writing, the most relevant IETF RFCs are: -.IP -RFC2409 The Internet Key Exchange (IKE) -.IP -RFC2408 Internet Security Association and Key Management Protocol (ISAKMP) -.IP -RFC2407 The Internet IP Security Domain of Interpretation for ISAKMP -.LP -The FreeS/WAN web site -and the mailing lists described there. -.SH HISTORY -This code is released under the GPL terms. -See the accompanying file COPYING-2.0 for more details. -The GPL does NOT apply to those pieces of code written by others -which are included in this distribution, except as noted by the -individual authors. -.LP -This software was originally written -for the FreeS/WAN project - -by Angelos D. Keromytis -(angelos@dsl.cis.upenn.edu), in May/June 1997, in Athens, Greece. -Thanks go to John Ioannidis for his help. -.LP -It is currently (2000) -being developed and maintained by D. Hugh Redelmeier -(hugh@mimosa.com), in Canada. The regulations of Greece and Canada -allow us to make the code freely redistributable. -.LP -Kai Martius (admin@imib.med.tu-dresden.de) contributed the initial -version of the code supporting PFS. -.LP -Richard Guy Briggs and Peter Onion - added the PFKEY2 support. -.LP -We gratefully acknowledge that we use parts of Eric Young's \fIlibdes\fP -package; see \fI../libdes/COPYRIGHT\fP. -.SH BUGS -.BR pluto -is a work-in-progress. It currently has many limitations. -For example, it ignores notification messages that it receives, and -it generates only Delete Notifications and those only for IPSEC SAs. -.LP -\fBpluto\fP does not support the Commit Flag. -The Commit Flag is a bad feature of the IKE protocol. -It isn't protected -- neither encrypted nor authenticated. -A man in the middle could turn it on, leading to DoS. -We just ignore it, with a warning. -This should let us interoperate with -implementations that insist on it, with minor damage. -.LP -\fBpluto\fP does not check that the SA returned by the Responder -is actually one that was proposed. It only checks that the SA is -acceptable. The difference is not large, but can show up in attributes -such as SA lifetime. -.LP -There is no good way for a connection to be automatically terminated. -This is a problem for Road Warrior and Opportunistic connections. -The \fB\-\-dontrekey\fP option does prevent the SAs from -being rekeyed on expiry. -Additionally, if a Road Warrior connection has a client subnet with a fixed IP -address, a negotiation with that subnet will cause any other -connection instantiations with that same subnet to be unoriented -(deleted, in effect). -See also the \-\-uniqueids option for an extension of this. -.LP -When \fBpluto\fP sends a message to a peer that has disappeared, -\fBpluto\fP receives incomplete information from the kernel, so it -logs the unsatisfactory message ``some IKE message we sent has been -rejected with ECONNREFUSED (kernel supplied no details)''. John -Denker suggests that this command is useful for tracking down the -source of these problems: -.br - tcpdump \-i eth0 icmp[0] != 8 and icmp[0] != 0 -.br -Substitute your public interface for eth0 if it is different. -.LP -The word ``authenticate'' is used for two different features. We must -authenticate each IKE peer to the other. This is an important task of -Phase 1. Each packet must be authenticated, both in IKE and in IPsec, -and the method for IPsec is negotiated as an AH SA or part of an ESP SA. -Unfortunately, the protocol has no mechanism for authenticating the Phase 2 -identities. -.LP -Bugs should be reported to the mailing list. -Caution: we cannot accept -actual code from US residents, or even US citizens living outside the -US, because that would bring FreeS/WAN under US export law. Some -other countries cause similar problems. In general, we would prefer -that you send detailed problem reports rather than code: we want -FreeS/WAN to be unquestionably freely exportable, which means being -very careful about where the code comes from, and for a small bug fix, -that is often more time-consuming than just reinventing the fix -ourselves. diff --git a/src/pluto/pluto.c b/src/pluto/pluto.c deleted file mode 100644 index 66fdb30b9..000000000 --- a/src/pluto/pluto.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "pluto.h" - -#include - -typedef struct private_pluto_t private_pluto_t; - -/** - * Private additions to pluto_t. - */ -struct private_pluto_t { - - /** - * Public members of pluto_t. - */ - pluto_t public; -}; - -/** - * Single instance of pluto_t. - */ -pluto_t *pluto; - -/** - * Described in header. - */ -void pluto_deinit() -{ - private_pluto_t *this = (private_pluto_t*)pluto; - this->public.events->destroy(this->public.events); - this->public.xauth->destroy(this->public.xauth); - free(this); - pluto = NULL; -} - -/** - * Described in header. - */ -bool pluto_init(char *file) -{ - private_pluto_t *this; - - INIT(this, - .public = { - .events = event_queue_create(), - .xauth = xauth_manager_create(), - }, - ); - pluto = &this->public; - - if (lib->integrity && - !lib->integrity->check_file(lib->integrity, "pluto", file)) - { - DBG1(DBG_LIB, "integrity check of pluto failed"); - return FALSE; - } - return TRUE; -} - diff --git a/src/pluto/pluto.h b/src/pluto/pluto.h deleted file mode 100644 index 2440093ca..000000000 --- a/src/pluto/pluto.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup pluto pluto - * - * @defgroup xauth xauth - * @ingroup pluto - * - * @defgroup pplugins plugins - * @ingroup pluto - * - * @addtogroup pluto - * @{ - */ - -#ifndef PLUTO_H_ -#define PLUTO_H_ - -typedef struct pluto_t pluto_t; - -#include -#include - -#include - -/** - * Pluto daemon support object. - */ -struct pluto_t { - - /** - * event queue (callbacks, executed by the pluto main thread) - */ - event_queue_t *events; - - /** - * manager for payload attributes - */ - xauth_manager_t *xauth; - -}; - -/** - * The single instance of pluto_t. - * - * Set between calls to pluto_init() and pluto_deinit() calls. - */ -extern pluto_t *pluto; - -/** - * Initialize pluto. - * - * @return FALSE if integrity check failed - */ -bool pluto_init(char *file); - -/** - * Deinitialize pluto. - */ -void pluto_deinit(void); - -#endif /** PLUTO_H_ @}*/ - diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c deleted file mode 100644 index dbc857ce2..000000000 --- a/src/pluto/plutomain.c +++ /dev/null @@ -1,852 +0,0 @@ -/* Pluto main program - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* missing from on old systems */ -#include -#include -#include -#include -#include - -#ifdef CAPABILITIES -#ifdef HAVE_SYS_CAPABILITY_H -#include -#endif /* HAVE_SYS_CAPABILITY_H */ -#endif /* CAPABILITIES */ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "ca.h" -#include "certs.h" -#include "ac.h" -#include "connections.h" -#include "foodgroups.h" -#include "packet.h" -#include "demux.h" /* needs packet.h */ -#include "server.h" -#include "kernel.h" -#include "log.h" -#include "keys.h" -#include "adns.h" /* needs */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "state.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "ocsp.h" -#include "crl.h" -#include "fetch.h" -#include "crypto.h" -#include "nat_traversal.h" -#include "virtual.h" -#include "timer.h" -#include "vendor.h" -#include "builder.h" -#include "whack_attribute.h" -#include "pluto.h" - -#ifdef ANDROID -#include /* for AID_VPN */ -#endif - -/** - * Number of threads in the thread pool, if not specified in config. - */ -#define DEFAULT_THREADS 4 - -/** - * PID file, in which pluto stores its process id - */ -static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX; - -/** - * TRUE if the lock has been checked. This helps to avoid any unintended - * deletion of the lock or control socket. - */ -static bool pluto_lock_checked = FALSE; - -/** - * Global reference to PID file (required to truncate, if undeletable) - */ -static FILE *pidfile = NULL; - - -static void usage(const char *mess) -{ - if (mess != NULL && *mess != '\0') - fprintf(stderr, "%s\n", mess); - fprintf(stderr - , "Usage: pluto" - " [--help]" - " [--version]" - " [--optionsfrom ]" - " \\\n\t" - "[--nofork]" - " [--stderrlog]" - " [--nocrsend]" - " \\\n\t" - "[--strictcrlpolicy]" - " [--crlcheckinterval ]" - " [--cachecrls]" - " [--uniqueids]" - " \\\n\t" - "[--interface ]" - " [--ikeport ]" - " \\\n\t" - "[--ctlbase ]" - " \\\n\t" - "[--perpeerlogbase ] [--perpeerlog]" - " \\\n\t" - "[--secretsfile ]" - " [--policygroupsdir ]" - " \\\n\t" - "[--adns ]" - "[--pkcs11module ]" - "[--pkcs11keepstate]" - "[--pkcs11initargs ]" -#ifdef DEBUG - " \\\n\t" - "[--debug-none]" - " [--debug-all]" - " \\\n\t" - "[--debug-raw]" - " [--debug-crypt]" - " [--debug-parsing]" - " [--debug-emitting]" - " \\\n\t" - "[--debug-control]" - " [--debug-lifecycle]" - " [--debug-kernel]" - " [--debug-dns]" - " \\\n\t" - "[--debug-oppo]" - " [--debug-controlmore]" - " [--debug-private]" - " [--debug-natt]" -#endif - " \\\n\t" - "[--nat_traversal] [--keep_alive ]" - " \\\n\t" - "[--force_keepalive] [--disable_port_floating]" - " \\\n\t" - "[--virtual_private ]" - "\n" - "strongSwan "VERSION"\n"); - exit_pluto(mess == NULL? 0 : 1); -} - -static bool check_lock() -{ - struct stat stb; - FILE *fpid; - - if (stat(pluto_lock, &stb) == 0) - { - fpid = fopen(pluto_lock, "r"); - if (fpid) - { - char buf[64]; - pid_t pid = 0; - - memset(buf, 0, sizeof(buf)); - if (fread(buf, 1, sizeof(buf), fpid)) - { - buf[sizeof(buf) - 1] = '\0'; - pid = atoi(buf); - } - fclose(fpid); - if (pid && kill(pid, 0) == 0) - { /* such a process is running */ - return TRUE; - } - } - fprintf(stderr, "pluto: removing lock file \"%s\", process not " - "running\n", pluto_lock); - unlink(pluto_lock); - } - pluto_lock_checked = TRUE; - return FALSE; -} - -static void fill_lock(void) -{ - pidfile = fopen(pluto_lock, "w"); - if (pidfile) - { - fprintf(pidfile, "%u\n", (u_int)getpid()); - fflush(pidfile); - } - /* keep pidfile open so we can truncate it, if we cannot delete it */ -} - -static void delete_lock(void) -{ - /* because unlinking the PID file may fail, we truncate it to ensure the - * daemon can be properly restarted. one probable cause for this is the - * combination of not running as root and the effective user lacking - * permissions on the parent dir(s) of the PID file */ - if (pluto_lock_checked) - { - if (pidfile) - { - ignore_result(ftruncate(fileno(pidfile), 0)); - fclose(pidfile); - } - unlink(pluto_lock); - /* delete this here to avoid that exit_pluto calls delete the socket */ - delete_ctl_socket(); - } -} - - -/* by default pluto sends certificate requests to its peers */ -bool no_cr_send = FALSE; - -/* by default the CRL policy is lenient */ -bool strict_crl_policy = FALSE; - -/* by default CRLs are cached locally as files */ -bool cache_crls = FALSE; - -/* by default pluto does not check crls dynamically */ -long crl_check_interval = 0; - -/* path to the PKCS#11 module */ -char *pkcs11_module_path = NULL; - -/* by default pluto logs out after every smartcard use */ -bool pkcs11_keep_state = FALSE; - -/* by default pluto does not allow pkcs11 proxy access via whack */ -bool pkcs11_proxy = FALSE; - -/* argument string to pass to PKCS#11 module. - * Not used for compliant modules, just for NSS softoken - */ -static const char *pkcs11_init_args = NULL; - -/* options read by optionsfrom */ -options_t *options; - -int main(int argc, char **argv) -{ - bool fork_desired = TRUE; - bool log_to_stderr_desired = FALSE; - bool nat_traversal = FALSE; - bool nat_t_spf = TRUE; /* support port floating */ - unsigned int keep_alive = 0; - bool force_keepalive = FALSE; - char *virtual_private = NULL; -#ifdef CAPABILITIES - int keep[] = { - CAP_NET_ADMIN, - CAP_NET_BIND_SERVICE, -#ifdef ANDROID - CAP_NET_RAW, -#endif - }; -#endif /* CAPABILITIES */ - - /* initialize library and optionsfrom */ - if (!library_init(NULL)) - { - library_deinit(); - exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); - } - if (!libhydra_init("pluto")) - { - libhydra_deinit(); - library_deinit(); - exit(SS_RC_INITIALIZATION_FAILED); - } - if (!pluto_init(argv[0])) - { - pluto_deinit(); - libhydra_deinit(); - library_deinit(); - exit(SS_RC_DAEMON_INTEGRITY); - } - options = options_create(); - - /* handle arguments */ - for (;;) - { -# define DBG_OFFSET 256 - static const struct option long_opts[] = { - /* name, has_arg, flag, val */ - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'v' }, - { "optionsfrom", required_argument, NULL, '+' }, - { "nofork", no_argument, NULL, 'd' }, - { "stderrlog", no_argument, NULL, 'e' }, - { "nocrsend", no_argument, NULL, 'c' }, - { "strictcrlpolicy", no_argument, NULL, 'r' }, - { "crlcheckinterval", required_argument, NULL, 'x'}, - { "cachecrls", no_argument, NULL, 'C' }, - { "uniqueids", no_argument, NULL, 'u' }, - { "interface", required_argument, NULL, 'i' }, - { "ikeport", required_argument, NULL, 'p' }, - { "ctlbase", required_argument, NULL, 'b' }, - { "secretsfile", required_argument, NULL, 's' }, - { "foodgroupsdir", required_argument, NULL, 'f' }, - { "perpeerlogbase", required_argument, NULL, 'P' }, - { "perpeerlog", no_argument, NULL, 'l' }, - { "policygroupsdir", required_argument, NULL, 'f' }, - { "adns", required_argument, NULL, 'a' }, - { "pkcs11module", required_argument, NULL, 'm' }, - { "pkcs11keepstate", no_argument, NULL, 'k' }, - { "pkcs11initargs", required_argument, NULL, 'z' }, - { "pkcs11proxy", no_argument, NULL, 'y' }, - { "nat_traversal", no_argument, NULL, '1' }, - { "keep_alive", required_argument, NULL, '2' }, - { "force_keepalive", no_argument, NULL, '3' }, - { "disable_port_floating", no_argument, NULL, '4' }, - { "debug-natt", no_argument, NULL, '5' }, - { "virtual_private", required_argument, NULL, '6' }, -#ifdef DEBUG - { "debug-none", no_argument, NULL, 'N' }, - { "debug-all", no_argument, NULL, 'A' }, - { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET }, - { "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET }, - { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET }, - { "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET }, - { "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET }, - { "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET }, - { "debug-klips", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, - { "debug-kernel", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, - { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET }, - { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET }, - { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET }, - { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET }, - - { "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET }, - { "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET }, - { "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET }, - { "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET }, -#endif - { 0,0,0,0 } - }; - /* Note: we don't like the way short options get parsed - * by getopt_long, so we simply pass an empty string as - * the list. It could be "hvdenp:l:s:" "NARXPECK". - */ - int c = getopt_long(argc, argv, "", long_opts, NULL); - - /* Note: "breaking" from case terminates loop */ - switch (c) - { - case EOF: /* end of flags */ - break; - - case 0: /* long option already handled */ - continue; - - case ':': /* diagnostic already printed by getopt_long */ - case '?': /* diagnostic already printed by getopt_long */ - usage(""); - break; /* not actually reached */ - - case 'h': /* --help */ - usage(NULL); - break; /* not actually reached */ - - case 'v': /* --version */ - { - const char **sp = ipsec_copyright_notice(); - - printf("strongSwan "VERSION"%s\n", compile_time_interop_options); - for (; *sp != NULL; sp++) - puts(*sp); - } - exit_pluto(0); - break; /* not actually reached */ - - case '+': /* --optionsfrom */ - if (!options->from(options, optarg, &argc, &argv, optind)) - { - exit_pluto(1); - } - continue; - - case 'd': /* --nofork*/ - fork_desired = FALSE; - continue; - - case 'e': /* --stderrlog */ - log_to_stderr_desired = TRUE; - continue; - - case 'c': /* --nocrsend */ - no_cr_send = TRUE; - continue; - - case 'r': /* --strictcrlpolicy */ - strict_crl_policy = TRUE; - continue; - - case 'x': /* --crlcheckinterval