diff --git a/0001-restore-registration-algorithm-order.bug897512.patch b/0001-restore-registration-algorithm-order.bug897512.patch new file mode 100644 index 0000000..eb4ad60 --- /dev/null +++ b/0001-restore-registration-algorithm-order.bug897512.patch @@ -0,0 +1,413 @@ +From 76ad8a6f4c83c999b9eb6d1a3506b1a8e593307e Mon Sep 17 00:00:00 2001 +From: Tobias Brunner +Date: Fri, 20 Jun 2014 16:22:15 +0200 +Subject: [PATCH] Merge branch 'algorithm-order' +Upstream: yes +References: bsc#897512 + +Restores the behavior we had before 2e22333fb (except for RNGs), that is, +algorithms are stored in the registration order again. Which is not optimal +as we must rely on plugins to register them in a sensible order, but ordering +them by identifier definitely caused weaker algorithms to be proposed first +in the default proposal, which was even worse. +--- + src/libstrongswan/crypto/crypto_factory.c | 18 +- + src/libstrongswan/tests/Makefile.am | 1 + + .../tests/suites/test_crypto_factory.c | 312 +++++++++++++++++++++ + src/libstrongswan/tests/tests.h | 1 + + 4 files changed, 327 insertions(+), 5 deletions(-) + create mode 100644 src/libstrongswan/tests/suites/test_crypto_factory.c + +diff --git a/src/libstrongswan/crypto/crypto_factory.c b/src/libstrongswan/crypto/crypto_factory.c +index 6dea30e..96fbc0d 100644 +--- a/src/libstrongswan/crypto/crypto_factory.c ++++ b/src/libstrongswan/crypto/crypto_factory.c +@@ -392,10 +392,10 @@ METHOD(crypto_factory_t, create_dh, diffie_hellman_t*, + /** + * Insert an algorithm entry to a list + * +- * Entries are sorted by algorithm identifier (which is important for RNGs) +- * while maintaining the order in which algorithms were added, unless they were ++ * Entries maintain the order in which algorithms were added, unless they were + * benchmarked and speed is provided, which then is used to order entries of + * the same algorithm. ++ * An exception are RNG entries, which are sorted by algorithm identifier. + */ + static void add_entry(private_crypto_factory_t *this, linked_list_t *list, + int algo, const char *plugin_name, +@@ -403,6 +403,7 @@ static void add_entry(private_crypto_factory_t *this, linked_list_t *list, + { + enumerator_t *enumerator; + entry_t *entry, *current; ++ bool sort = (list == this->rngs), found = FALSE; + + INIT(entry, + .algo = algo, +@@ -415,12 +416,19 @@ static void add_entry(private_crypto_factory_t *this, linked_list_t *list, + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, ¤t)) + { +- if (current->algo > algo) ++ if (sort && current->algo > algo) + { + break; + } +- else if (current->algo == algo && speed && +- current->speed < speed) ++ else if (current->algo == algo) ++ { ++ if (speed > current->speed) ++ { ++ break; ++ } ++ found = TRUE; ++ } ++ else if (found) + { + break; + } +diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am +index 331a548..0bdf2b3 100644 +--- a/src/libstrongswan/tests/Makefile.am ++++ b/src/libstrongswan/tests/Makefile.am +@@ -42,6 +42,7 @@ tests_SOURCES = tests.h tests.c \ + suites/test_host.c \ + suites/test_hasher.c \ + suites/test_crypter.c \ ++ suites/test_crypto_factory.c \ + suites/test_pen.c \ + suites/test_asn1.c \ + suites/test_asn1_parser.c \ +diff --git a/src/libstrongswan/tests/suites/test_crypto_factory.c b/src/libstrongswan/tests/suites/test_crypto_factory.c +new file mode 100644 +index 0000000..94f45da +--- /dev/null ++++ b/src/libstrongswan/tests/suites/test_crypto_factory.c +@@ -0,0 +1,312 @@ ++/* ++ * Copyright (C) 2014 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 "test_suite.h" ++ ++#include ++ ++static rng_t *rng_create(rng_quality_t quality) ++{ ++ rng_quality_t *q = malloc_thing(rng_quality_t); ++ *q = quality; ++ return (rng_t*)q; ++} ++ ++static rng_t *rng_create_weak(rng_quality_t quality) ++{ ++ ck_assert(quality == RNG_WEAK); ++ return rng_create(RNG_WEAK); ++} ++ ++static rng_t *rng_create_strong(rng_quality_t quality) ++{ ++ ck_assert(quality <= RNG_STRONG); ++ return rng_create(RNG_STRONG); ++} ++ ++static rng_t *rng_create_true(rng_quality_t quality) ++{ ++ ck_assert(quality <= RNG_TRUE); ++ return rng_create(RNG_TRUE); ++} ++ ++static rng_t *rng_create_true_second(rng_quality_t quality) ++{ ++ fail("should never be called"); ++ return rng_create(RNG_TRUE); ++} ++ ++static rng_quality_t rng_weak = RNG_WEAK; ++static rng_quality_t rng_strong = RNG_STRONG; ++static rng_quality_t rng_true = RNG_TRUE; ++ ++static struct { ++ rng_quality_t *exp_weak; ++ rng_quality_t *exp_strong; ++ rng_quality_t *exp_true; ++ struct { ++ rng_quality_t *q; ++ rng_constructor_t create; ++ } data[4]; ++} rng_data[] = { ++ { NULL, NULL, NULL, { ++ { NULL, NULL } ++ }}, ++ { &rng_weak, NULL, NULL, { ++ { &rng_weak, rng_create_weak }, ++ { NULL, NULL } ++ }}, ++ { &rng_strong, &rng_strong, NULL, { ++ { &rng_strong, rng_create_strong }, ++ { NULL, NULL } ++ }}, ++ { &rng_true, &rng_true, &rng_true, { ++ { &rng_true, rng_create_true }, ++ { NULL, NULL } ++ }}, ++ { &rng_true, &rng_true, &rng_true, { ++ { &rng_true, rng_create_true }, ++ { &rng_true, rng_create_true_second }, ++ { NULL, NULL } ++ }}, ++ { &rng_weak, &rng_true, &rng_true, { ++ { &rng_weak, rng_create_weak }, ++ { &rng_true, rng_create_true }, ++ { NULL, NULL } ++ }}, ++ { &rng_weak, &rng_strong, &rng_true, { ++ { &rng_true, rng_create_true }, ++ { &rng_strong, rng_create_strong }, ++ { &rng_weak, rng_create_weak }, ++ { NULL, NULL } ++ }}, ++ { &rng_weak, &rng_strong, &rng_true, { ++ { &rng_weak, rng_create_weak }, ++ { &rng_strong, rng_create_strong }, ++ { &rng_true, rng_create_true }, ++ { NULL, NULL } ++ }}, ++}; ++ ++static void verify_rng(crypto_factory_t *factory, rng_quality_t request, ++ rng_quality_t *expected) ++{ ++ rng_quality_t *res; ++ ++ res = (rng_quality_t*)factory->create_rng(factory, request); ++ if (!expected) ++ { ++ ck_assert(!res); ++ } ++ else ++ { ++ ck_assert(res); ++ ck_assert_int_eq(*expected, *res); ++ free(res); ++ } ++} ++ ++START_TEST(test_create_rng) ++{ ++ crypto_factory_t *factory; ++ int i; ++ ++ factory = crypto_factory_create(); ++ for (i = 0; rng_data[_i].data[i].q; i++) ++ { ++ ck_assert(factory->add_rng(factory, *rng_data[_i].data[i].q, "test", ++ rng_data[_i].data[i].create)); ++ } ++ verify_rng(factory, RNG_WEAK, rng_data[_i].exp_weak); ++ verify_rng(factory, RNG_STRONG, rng_data[_i].exp_strong); ++ verify_rng(factory, RNG_TRUE, rng_data[_i].exp_true); ++ for (i = 0; rng_data[_i].data[i].q; i++) ++ { ++ factory->remove_rng(factory, rng_data[_i].data[i].create); ++ } ++ factory->destroy(factory); ++} ++END_TEST ++ ++static diffie_hellman_t *dh_create(char *plugin) ++{ ++ return (diffie_hellman_t*)plugin; ++} ++ ++static diffie_hellman_t *dh_create_modp1024(diffie_hellman_group_t group, ...) ++{ ++ ck_assert(group == MODP_1024_BIT); ++ return dh_create("plugin1"); ++} ++ ++static diffie_hellman_t *dh_create_modp1024_second(diffie_hellman_group_t group, ++ ...) ++{ ++ ck_assert(group == MODP_1024_BIT); ++ return dh_create("plugin2"); ++} ++ ++static diffie_hellman_t *dh_create_modp2048(diffie_hellman_group_t group, ...) ++{ ++ ck_assert(group == MODP_2048_BIT); ++ return dh_create("plugin1"); ++} ++ ++static diffie_hellman_t *dh_create_modp2048_second(diffie_hellman_group_t group, ++ ...) ++{ ++ ck_assert(group == MODP_2048_BIT); ++ return dh_create("plugin2"); ++} ++ ++static struct { ++ char *exp1024; ++ char *exp2048; ++ struct { ++ diffie_hellman_group_t g; ++ dh_constructor_t create; ++ char *plugin; ++ } data[4]; ++} dh_data[] = { ++ { NULL, NULL, { ++ { MODP_NONE, NULL, NULL } ++ }}, ++ { "plugin1", NULL, { ++ { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, ++ { MODP_NONE, NULL, NULL } ++ }}, ++ { "plugin1", NULL, { ++ { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, ++ { MODP_1024_BIT, dh_create_modp1024_second, "plugin2" }, ++ { MODP_NONE, NULL, NULL } ++ }}, ++ { "plugin2", NULL, { ++ { MODP_1024_BIT, dh_create_modp1024_second, "plugin2" }, ++ { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, ++ { MODP_NONE, NULL, NULL } ++ }}, ++ { "plugin1", "plugin1", { ++ { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, ++ { MODP_2048_BIT, dh_create_modp2048, "plugin1" }, ++ { MODP_NONE, NULL } ++ }}, ++ { "plugin1", "plugin1", { ++ { MODP_2048_BIT, dh_create_modp2048, "plugin1" }, ++ { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, ++ { MODP_NONE, NULL } ++ }}, ++ { "plugin1", "plugin1", { ++ { MODP_2048_BIT, dh_create_modp2048, "plugin1" }, ++ { MODP_2048_BIT, dh_create_modp2048_second, "plugin2" }, ++ { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, ++ { MODP_NONE, NULL } ++ }}, ++ { "plugin1", "plugin2", { ++ { MODP_2048_BIT, dh_create_modp2048_second, "plugin2" }, ++ { MODP_2048_BIT, dh_create_modp2048, "plugin1" }, ++ { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, ++ { MODP_NONE, NULL } ++ }}, ++}; ++ ++static void verify_dh(crypto_factory_t *factory, diffie_hellman_group_t request, ++ char *expected) ++{ ++ char *plugin; ++ ++ plugin = (char*)factory->create_dh(factory, request); ++ if (!expected) ++ { ++ ck_assert(!plugin); ++ } ++ else ++ { ++ ck_assert(plugin); ++ ck_assert_str_eq(expected, plugin); ++ } ++} ++ ++START_TEST(test_create_dh) ++{ ++ enumerator_t *enumerator; ++ crypto_factory_t *factory; ++ diffie_hellman_group_t group; ++ char *plugin; ++ int i, len = 0; ++ ++ ++ factory = crypto_factory_create(); ++ for (i = 0; dh_data[_i].data[i].g != MODP_NONE; i++) ++ { ++ ck_assert(factory->add_dh(factory, dh_data[_i].data[i].g, ++ dh_data[_i].data[i].plugin, ++ dh_data[_i].data[i].create)); ++ } ++ verify_dh(factory, MODP_1024_BIT, dh_data[_i].exp1024); ++ verify_dh(factory, MODP_2048_BIT, dh_data[_i].exp2048); ++ ++ len = countof(dh_data[_i].data); ++ enumerator = factory->create_dh_enumerator(factory); ++ for (i = 0; enumerator->enumerate(enumerator, &group, &plugin) && i < len;) ++ { ++ ck_assert_int_eq(dh_data[_i].data[i].g, group); ++ while (dh_data[_i].data[i].g == group) ++ { /* skip other entries by the same group */ ++ i++; ++ } ++ switch (group) ++ { ++ case MODP_1024_BIT: ++ ck_assert(dh_data[_i].exp1024); ++ ck_assert_str_eq(dh_data[_i].exp1024, plugin); ++ break; ++ case MODP_2048_BIT: ++ ck_assert(dh_data[_i].exp2048); ++ ck_assert_str_eq(dh_data[_i].exp2048, plugin); ++ break; ++ default: ++ fail("unexpected DH group"); ++ break; ++ } ++ } ++ ck_assert(!enumerator->enumerate(enumerator)); ++ ck_assert_int_eq(dh_data[_i].data[i].g, MODP_NONE); ++ enumerator->destroy(enumerator); ++ ++ for (i = 0; dh_data[_i].data[i].g != MODP_NONE; i++) ++ { ++ factory->remove_dh(factory, dh_data[_i].data[i].create); ++ } ++ factory->destroy(factory); ++} ++END_TEST ++ ++Suite *crypto_factory_suite_create() ++{ ++ Suite *s; ++ TCase *tc; ++ ++ s = suite_create("crypto-factory"); ++ ++ tc = tcase_create("create_rng"); ++ tcase_add_loop_test(tc, test_create_rng, 0, countof(rng_data)); ++ suite_add_tcase(s, tc); ++ ++ tc = tcase_create("create_dh"); ++ tcase_add_loop_test(tc, test_create_dh, 0, countof(dh_data)); ++ suite_add_tcase(s, tc); ++ ++ return s; ++} +diff --git a/src/libstrongswan/tests/tests.h b/src/libstrongswan/tests/tests.h +index 82a5137..ab0f642 100644 +--- a/src/libstrongswan/tests/tests.h ++++ b/src/libstrongswan/tests/tests.h +@@ -35,6 +35,7 @@ TEST_SUITE(host_suite_create) + TEST_SUITE(printf_suite_create) + TEST_SUITE(hasher_suite_create) + TEST_SUITE(crypter_suite_create) ++TEST_SUITE(crypto_factory_suite_create) + TEST_SUITE(pen_suite_create) + TEST_SUITE(asn1_suite_create) + TEST_SUITE(asn1_parser_suite_create) +-- +2.1.2 + diff --git a/README.SUSE b/README.SUSE index ae2311b..b0fe2e6 100644 --- a/README.SUSE +++ b/README.SUSE @@ -15,16 +15,40 @@ This requires adoption of either the "conn %default" or all other IKEv1 keyexchange=ikev1 +The charon daemon in strongswan 5.x versions supports IKEv1 and IKEv2, +thus a separate pluto IKEv1 daemon is not needed / not shipped any more. -The strongswan package does no provide any files any more, but triggers -the installation of both, IKEv1 (pluto) and IKEv2 (charon) daemons and the -traditional starter scripts inclusive of the /etc/init.d/ipsec init script -and /etc/ipsec.conf file. -There is a new strongswan-nm package with a NetworkManager plugin to -control the charon IKEv2 daemon through D-Bus, designed to work using the -NetworkManager-strongswan graphical user interface. +The strongswan package does not provide any files except of this README, +but triggers the installation of the charon daemon and the "traditional" +strongswan-ipsec package providing the "ipsec" script and service. +The ipsec.service is an alias link to the "strongswan.service" systemd +service unit and created by "systemctl enable strongswan.service". + + +There is a new strongswan-nm package with a NetworkManager specific charon-nm +binary controlling the charon daemon through D-Bus and designed to work using +the NetworkManager-strongswan graphical user interface. It does not depend on the traditional starter scripts, but on the IKEv2 charon daemon and plugins only. + +The stongswan-hmac package provides the fips hmac hash files, a _fipscheck +script and a /etc/strongswan.d/charon/zzz_fips-enforce.conf config file, +which disables all non-openssl algorithm implementations. + +When fips operation mode is enabled in the kernel using the fips=1 boot +parameter, the strongswan fips checks are executed in front of any start +action of the "ipsec" script provided by the "strongswan-ipsec" package +and a verification problem causes a failure as required by fips-140-2. +Further, it is not required to enable the fips_mode in the openssl plugin +(/etc/strongswan.d/charon/openssl.conf); the kernel entablement enables +it automatically as needed. + +The "ipsec _fipscheck" command allows to execute the fips checks manually +without a check if fips is enabled (/proc/sys/crypto/fips_enabled is 1), +e.g. for testing purposes. + + Have a lot of fun... + diff --git a/fips-enforce.conf b/fips-enforce.conf new file mode 100644 index 0000000..637b5c8 --- /dev/null +++ b/fips-enforce.conf @@ -0,0 +1,52 @@ +# +# When fips is enabled (fips=1 kernel parameter), only certified openssl +# and kernel crypto API (af-alg) algorithms are supported. +# +# The strongswan-hmac package is supposed to be used/installed when fips +# is enabled and provides the hmac hashes, a "ipsec _fipscheck" script +# verifying the components and this blacklist disabling other plugins +# providing further and/or alternative algorithm implementations. +# +gcrypt { + load = no +} +blowfish { + load = no +} +random { + load = no +} +des { + load = no +} +aes { + load = no +} +rc2 { + load = no +} +ctr { + load = no +} +cmac { + load = no +} +xcbc { + load = no +} +md4 { + load = no +} +md5 { + load = no +} +sha1 { + load = no +} +sha2 { + load = no +} +ccm { + load = no +} + diff --git a/fipscheck.sh.in b/fipscheck.sh.in new file mode 100644 index 0000000..54c989c --- /dev/null +++ b/fipscheck.sh.in @@ -0,0 +1,69 @@ +#! /bin/bash +# +# Copyright (C) 2014 SUSE LINUX GmbH, Nuernberg, Germany. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, see . +# +# Author: Marius Tomaschewski +# +IPSEC_DIR="@IPSEC_DIR@" +IPSEC_LIBDIR="@IPSEC_LIBDIR@" +IPSEC_BINDIR="@IPSEC_BINDIR@" +IPSEC_SBINDIR="@IPSEC_SBINDIR@" +fipscheck_bin="/usr/bin/fipscheck" + +# minimal usage hint +if test $# -gt 0 ; then + echo "usage: ipsec _fipscheck" >&2 + exit 2 +fi + +# +# "ipsec xxx" starts this script only if crypto/fips_enabled=1, +# except while a manually enforced check via "ipsec _fipscheck". +# +#read 2>/dev/null fips_enabled < /proc/sys/crypto/fips_enabled +#test "X$fips_enabled" = "X1" || exit 0 + +# verify that fipscheck is installed +test -x "$fipscheck_bin" || { + test "X$FIPSCHECK_DEBUG" = "Xerror" && \ + echo "${0##*/}: $fipscheck_bin utility missed" >&2 + exit 4 +} + +shopt -s nullglob + +files=() +for h in ${IPSEC_DIR}/.*.hmac \ + ${IPSEC_LIBDIR}/.*.hmac \ + ${IPSEC_LIBDIR}/imcvs/.*.hmac \ + ${IPSEC_LIBDIR}/plugins/.*.hmac \ + ${IPSEC_SBINDIR}/.ipsec.hmac \ + ; +do + dir="${h%/*}" + name="${h##*/.}" + file="${dir}/${name%.hmac}" + # some part is not installed + test -f "${file}" && files+=("$file") +done + +if test ${#files[@]} -gt 0 ; then + $fipscheck_bin ${files[@]} ; exit $? +elif test "X$FIPSCHECK_DEBUG" = "Xerror" ; then + echo "${0##*/}: unable to find any checksum/hmac file" >&2 +fi +exit 3 + diff --git a/strongswan.changes b/strongswan.changes index f90a5e1..f34fb6a 100644 --- a/strongswan.changes +++ b/strongswan.changes @@ -1,3 +1,25 @@ +------------------------------------------------------------------- +Thu Nov 20 07:43:43 UTC 2014 - mt@suse.de + +- Added generation of fips hmac hash files using fipshmac utility + and a _fipscheck script to verify binaries/libraries/plugings + shipped in the strongswan-hmac package. + With enabled fips in the kernel, the ipsec script will call it + before any action or in a enforced/manual "ipsec _fipscheck" call. + Added config file to load openssl and kernel af-alg plugins, but + not all the other modules which provide further/alternative algs. + Applied a filter disallowing non-approved algorithms in fips mode. + (fate#316931,bnc#856322). + [+ strongswan_fipscheck.patch, strongswan_fipsfilter.patch] +- Fixed file list in the optional (disabled) strongswan-test package. +- Fixed build of the strongswan built-in integrity checksum library + and enabled building it only on architectures tested to work. +- Fix to use bug number 897048 instead 856322 in last changes entry. +- Applied an upstream patch reverting to store algorithms in the + registration order again as ordering them by identifier caused + weaker algorithms to be proposed first by default (bsc#897512). + [+0001-restore-registration-algorithm-order.bug897512.patch] + ------------------------------------------------------------------- Fri Sep 26 16:02:09 UTC 2014 - mt@suse.de diff --git a/strongswan.spec b/strongswan.spec index 6a7587a..5edb05c 100644 --- a/strongswan.spec +++ b/strongswan.spec @@ -31,6 +31,11 @@ Release: 0 %else %bcond_with tests %endif +%ifarch %{ix86} ppc64le +%bcond_without integrity +%else +%bcond_with integrity +%endif %if 0%{suse_version} > 1110 %bcond_without farp %bcond_without afalg @@ -62,8 +67,13 @@ Source2: %{name}.init.in Source3: %{name}-%{version}-rpmlintrc Source4: README.SUSE Source5: %{name}.keyring +Source6: fipscheck.sh.in +Source7: fips-enforce.conf Patch1: %{name}_modprobe_syslog.patch Patch2: %{name}_ipsec_service.patch +Patch3: %{name}_fipscheck.patch +Patch4: %{name}_fipsfilter.patch +Patch5: 0001-restore-registration-algorithm-order.bug897512.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: bison BuildRequires: curl-devel @@ -100,6 +110,10 @@ BuildRequires: iptables %else %{!?_rundir: %global _rundir /var/run} %endif +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: fipscheck +BuildRequires: libtool %description StrongSwan is an OpenSource IPsec-based VPN Solution for Linux @@ -168,6 +182,8 @@ This package provides the strongswan library and plugins. %package hmac Summary: HMAC files for FIPS-140-2 integrity Group: Productivity/Networking/Security +Requires: fipscheck +Requires: strongswan-ipsec = %{version} Requires: strongswan-libs0 = %{version} %description hmac @@ -257,17 +273,27 @@ and the load testing plugin for IKEv2 daemon. %setup -q -n %{name}-%{upstream_version} %patch1 -p0 %patch2 -p0 +%patch3 -p0 +%patch4 -p1 +%patch5 -p1 sed -e 's|@libexecdir@|%_libexecdir|g' \ < $RPM_SOURCE_DIR/strongswan.init.in \ > strongswan.init +sed -e 's|@IPSEC_DIR@|%{_libexecdir}/ipsec|g' \ + -e 's|@IPSEC_LIBDIR@|%{_libdir}/ipsec|g' \ + -e 's|@IPSEC_SBINDIR@|%{_sbindir}|g' \ + -e 's|@IPSEC_BINDIR@|%{_bindir}|g' \ + < $RPM_SOURCE_DIR/fipscheck.sh.in \ + > _fipscheck %build CFLAGS="$RPM_OPT_FLAGS -W -Wall -Wno-pointer-sign -Wno-strict-aliasing -Wno-unused-parameter" export RPM_OPT_FLAGS CFLAGS -#libtoolize --force -#autoreconf +autoreconf --force --install %configure \ +%if %{with integrity} --enable-integrity-test \ +%endif --with-capabilities=libcap \ --with-plugindir=%{strongswan_plugins} \ --with-resolv-conf=%{_rundir}/%{name}/resolv.conf \ @@ -368,8 +394,36 @@ install -m755 strongswan.init ${RPM_BUILD_ROOT}%{_sysconfdir}/init.d/ipsec ln -s %{_sysconfdir}/init.d/ipsec ${RPM_BUILD_ROOT}%{_sbindir}/rcipsec %endif # +# Ensure, plugin -> library dependencies can be resolved +# (e.g. libtls) to avoid plugin segment checksum errors. +# +LD_LIBRARY_PATH="$RPM_BUILD_ROOT-$$%{strongswan_libdir}" \ make install DESTDIR="$RPM_BUILD_ROOT" # +# checksums are calculated during make install using the +# installed binaries/libraries... but find-debuginfo.sh +# extracts debuginfo/debugsource breaking file checksums. +# let find-debuginfo.sh run on a build root copy and then +# calculate the checksums. +# +%if %{with integrity} +%{?__debug_package: + if test -x %{_rpmconfigdir}/find-debuginfo.sh ; then + cp -a "${RPM_BUILD_ROOT}" "${RPM_BUILD_ROOT}-$$" + RPM_BUILD_ROOT="$RPM_BUILD_ROOT-$$" \ + %{_rpmconfigdir}/find-debuginfo.sh \ + %{?_find_debuginfo_opts} "${RPM_BUILD_ROOT}-$$" + make -C src/checksum clean + rm -f src/checksum/checksum_builder + LD_LIBRARY_PATH="$RPM_BUILD_ROOT-$$%{strongswan_libdir}" \ + make -C src/checksum install DESTDIR="$RPM_BUILD_ROOT-$$" + mv "$RPM_BUILD_ROOT-$$%{strongswan_libdir}/libchecksum.so" \ + "$RPM_BUILD_ROOT%{strongswan_libdir}/libchecksum.so" + rm -rf "${RPM_BUILD_ROOT}-$$" + fi +} +%endif +# rm -f ${RPM_BUILD_ROOT}%{_sysconfdir}/ipsec.secrets cat << EOT > ${RPM_BUILD_ROOT}%{_sysconfdir}/ipsec.secrets # @@ -400,6 +454,32 @@ install -c -m644 ${RPM_SOURCE_DIR}/README.SUSE \ %{__install} -d -m 0755 %{buildroot}%{_tmpfilesdir} echo 'd %{_rundir}/%{name} 0770 root root' > %{buildroot}%{_tmpfilesdir}/%{name}.conf %endif +# +# note: keep the following, _fipscheck's and file lists in sync +# +install -c -m750 _fipscheck ${RPM_BUILD_ROOT}%{_libexecdir}/ipsec/ +install -c -m644 ${RPM_SOURCE_DIR}/fips-enforce.conf \ + ${RPM_BUILD_ROOT}%{strongswan_configs}/charon/zzz_fips-enforce.conf +# create fips hmac hashes _after_ install post run +%{expand:%%global __os_install_post {%__os_install_post + for f in $RPM_BUILD_ROOT%{strongswan_libdir}/lib*.so.*.*.* \ + $RPM_BUILD_ROOT%{strongswan_libdir}/imcvs/*.so \ + $RPM_BUILD_ROOT%{strongswan_plugins}/*.so \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/charon \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/charon-nm \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/stroke \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/starter \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/pool \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/scepclient \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/pt-tls-client \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/imv_policy_manager \ + $RPM_BUILD_ROOT%{_libexecdir}/ipsec/_fipscheck \ + $RPM_BUILD_ROOT%{_sbindir}/ipsec \ + ; + do + /usr/bin/fipshmac "$f" + done +}} %post libs0 /sbin/ldconfig @@ -449,6 +529,18 @@ fi %files hmac %defattr(-,root,root) +%dir %{strongswan_configs} +%dir %{strongswan_configs}/charon +%config(noreplace) %attr(600,root,root) %{strongswan_configs}/charon/zzz_fips-enforce.conf +%dir %{strongswan_libdir} +%{strongswan_libdir}/.*.hmac +%{strongswan_libdir}/imcvs/.*.hmac +%dir %{strongswan_plugins} +%{strongswan_plugins}/.*.hmac +%dir %{_libexecdir}/ipsec +%{_libexecdir}/ipsec/_fipscheck +%{_libexecdir}/ipsec/.*.hmac +%{_sbindir}/.ipsec.hmac %files ipsec %defattr(-,root,root) @@ -618,7 +710,9 @@ fi %config(noreplace) %attr(600,root,root) %{strongswan_configs}/charon/xauth-pam.conf %config(noreplace) %attr(600,root,root) %{strongswan_configs}/charon/xcbc.conf %dir %{strongswan_libdir} +%if %{with integrity} %{strongswan_libdir}/libchecksum.so +%endif %{strongswan_libdir}/libcharon.so.* %{strongswan_libdir}/libhydra.so.* %{strongswan_libdir}/libpttls.so.* @@ -886,6 +980,18 @@ fi %files tests %defattr(-,root,root) +%dir %{strongswan_configs} +%dir %{strongswan_configs}/charon +%{strongswan_configs}/charon/load-tester.conf +%{strongswan_configs}/charon/test-vectors.conf +%dir %{strongswan_templates} +%dir %{strongswan_templates}/config +%dir %{strongswan_templates}/config/plugins +%{strongswan_templates}/config/plugins/load-tester.conf +%{strongswan_templates}/config/plugins/test-vectors.conf +%dir %{_libexecdir}/ipsec +%{_libexecdir}/ipsec/conftest +%{_libexecdir}/ipsec/load-tester %dir %{strongswan_libdir} %dir %{strongswan_plugins} %{strongswan_plugins}/libstrongswan-load-tester.so diff --git a/strongswan_fipscheck.patch b/strongswan_fipscheck.patch new file mode 100644 index 0000000..b49cbd0 --- /dev/null +++ b/strongswan_fipscheck.patch @@ -0,0 +1,89 @@ +--- src/ipsec/_ipsec.in ++++ src/ipsec/_ipsec.in 2014/11/07 11:28:25 +@@ -44,6 +44,26 @@ export IPSEC_DIR IPSEC_BINDIR IPSEC_SBIN + + IPSEC_DISTRO="Institute for Internet Technologies and Applications\nUniversity of Applied Sciences Rapperswil, Switzerland" + ++fipscheck() ++{ ++ # when fips operation mode is not enabled, just report OK ++ read 2>/dev/null fips_enabled < /proc/sys/crypto/fips_enabled ++ test "X$fips_enabled" = "X1" || return 0 ++ ++ # complain when _fipscheck is missed ++ test -x "$IPSEC_DIR/_fipscheck" || { ++ echo "ipsec: please install strongswan-hmac package required in fips mode" >&2 ++ return 4 ++ } ++ ++ # now execute it ++ $IPSEC_DIR/_fipscheck || { ++ rc=$? ++ echo "ipsec: strongSwan fips file integrity check failed" >&2 ++ return $rc ++ } ++} ++ + case "$1" in + '') + echo "Usage: $IPSEC_SCRIPT command argument ..." +@@ -166,6 +186,7 @@ rereadall|purgeocsp|listcounters|resetco + shift + if [ -e $IPSEC_CHARON_PID ] + then ++ fipscheck || exit $? + $IPSEC_STROKE "$op" "$@" + rc="$?" + fi +@@ -175,6 +196,7 @@ purgeike|purgecrls|purgecerts) + rc=7 + if [ -e $IPSEC_CHARON_PID ] + then ++ fipscheck || exit $? + $IPSEC_STROKE "$1" + rc="$?" + fi +@@ -208,6 +230,7 @@ route|unroute) + fi + if [ -e $IPSEC_CHARON_PID ] + then ++ fipscheck || exit $? + $IPSEC_STROKE "$op" "$1" + rc="$?" + fi +@@ -217,6 +240,7 @@ secrets) + rc=7 + if [ -e $IPSEC_CHARON_PID ] + then ++ fipscheck || exit $? + $IPSEC_STROKE rereadsecrets + rc="$?" + fi +@@ -224,6 +248,7 @@ secrets) + ;; + start) + shift ++ fipscheck || exit $? + if [ -d /var/lock/subsys ]; then + touch /var/lock/subsys/ipsec + fi +@@ -297,6 +322,7 @@ up) + rc=7 + if [ -e $IPSEC_CHARON_PID ] + then ++ fipscheck || exit $? + $IPSEC_STROKE up "$1" + rc="$?" + fi +@@ -332,6 +358,11 @@ esac + cmd="$1" + shift + ++case $cmd in ++_fipscheck|_copyright|pki) ;; ++*) fipscheck || exit $? ;; ++esac ++ + path="$IPSEC_DIR/$cmd" + + if [ ! -x "$path" ] diff --git a/strongswan_fipsfilter.patch b/strongswan_fipsfilter.patch new file mode 100644 index 0000000..81eee37 --- /dev/null +++ b/strongswan_fipsfilter.patch @@ -0,0 +1,254 @@ +diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c +index 2ecdb4f..85767ab 100644 +--- a/src/libcharon/config/proposal.c ++++ b/src/libcharon/config/proposal.c +@@ -26,6 +26,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP, + "PROTO_NONE", +@@ -185,6 +190,130 @@ METHOD(proposal_t, strip_dh, void, + enumerator->destroy(enumerator); + } + ++static bool kernel_fips_enabled(void) ++{ ++ char buf[1] = { '\0' }; ++ int fd; ++ ++ fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY); ++ if (fd >= 0) { ++ while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR); ++ close(fd); ++ } ++ return buf[0] == '1'; ++} ++ ++static bool fips_enabled(void) ++{ ++ static int enabled = -1; ++ if (enabled == -1) ++ enabled = kernel_fips_enabled(); ++ return enabled; ++} ++ ++static bool fips_filter(protocol_id_t protocol, transform_type_t type, u_int16_t alg) ++{ ++ switch (protocol) ++ { ++ case PROTO_IKE: ++ case PROTO_ESP: ++ case PROTO_AH: ++ break; ++ default: ++ /* not applicable protocol */ ++ return TRUE; ++ } ++ ++ switch (type) ++ { ++ case ENCRYPTION_ALGORITHM: ++ switch (alg) ++ { ++ /* crypter */ ++ case ENCR_3DES: ++ case ENCR_AES_CBC: ++ case ENCR_AES_CTR: ++ /* aead */ ++ case ENCR_AES_GCM_ICV8: ++ case ENCR_AES_GCM_ICV12: ++ case ENCR_AES_GCM_ICV16: ++ case ENCR_AES_CCM_ICV8: ++ case ENCR_AES_CCM_ICV12: ++ case ENCR_AES_CCM_ICV16: ++ return TRUE; ++ default: ++ break; ++ } ++ break; ++ case INTEGRITY_ALGORITHM: ++ switch (alg) ++ { ++ case AUTH_HMAC_SHA1_96: ++ case AUTH_HMAC_SHA1_160: ++ case AUTH_HMAC_SHA2_256_96: ++ case AUTH_HMAC_SHA2_256_128: ++ case AUTH_HMAC_SHA2_384_192: ++ case AUTH_HMAC_SHA2_512_256: ++ case AUTH_AES_CMAC_96: ++ return TRUE; ++ default: ++ break; ++ } ++ break; ++ case PSEUDO_RANDOM_FUNCTION: ++ switch (alg) ++ { ++ case PRF_HMAC_SHA1: ++ case PRF_HMAC_SHA2_256: ++ case PRF_HMAC_SHA2_384: ++ case PRF_HMAC_SHA2_512: ++ case PRF_AES128_CMAC: ++ return TRUE; ++ default: ++ break; ++ } ++ break; ++ case DIFFIE_HELLMAN_GROUP: ++ switch (alg) ++ { ++ case MODP_1024_BIT: ++ case MODP_1536_BIT: ++ case MODP_2048_BIT: ++ case MODP_3072_BIT: ++ case MODP_4096_BIT: ++ case MODP_8192_BIT: ++ case MODP_1024_160: ++ case MODP_2048_224: ++ case MODP_2048_256: ++ case ECP_192_BIT: ++ case ECP_224_BIT: ++ case ECP_256_BIT: ++ case ECP_384_BIT: ++ case ECP_521_BIT: ++ case ECP_224_BP: ++ case ECP_256_BP: ++ case ECP_384_BP: ++ case ECP_512_BP: ++ return TRUE; ++ default: ++ break; ++ } ++ break; ++ case EXTENDED_SEQUENCE_NUMBERS: ++ switch (alg) ++ { ++ case EXT_SEQ_NUMBERS: ++ case NO_EXT_SEQ_NUMBERS: ++ return TRUE; ++ default: ++ break; ++ } ++ default: ++ break; ++ } ++ return !fips_enabled(); ++} ++ + /** + * Select a matching proposal from this and other, insert into selected. + */ +@@ -500,6 +629,11 @@ static bool add_string_algo(private_proposal_t *this, const char *alg) + return FALSE; + } + ++ if (!fips_filter(this->protocol, token->type, token->algorithm)) ++ { ++ DBG1(DBG_CFG, "algorithm '%s' not permitted in fips mode", alg); ++ return FALSE; ++ } + add_algorithm(this, token->type, token->algorithm, token->keysize); + + return TRUE; +@@ -639,6 +773,8 @@ static void proposal_add_supported_ike(private_proposal_t *this) + enumerator = lib->crypto->create_crypter_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &encryption, &plugin_name)) + { ++ if (!fips_filter(PROTO_IKE, ENCRYPTION_ALGORITHM, encryption)) ++ continue; + switch (encryption) + { + case ENCR_AES_CBC: +@@ -665,6 +801,9 @@ static void proposal_add_supported_ike(private_proposal_t *this) + enumerator = lib->crypto->create_aead_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &encryption, &plugin_name)) + { ++ if (!fips_filter(PROTO_IKE, ENCRYPTION_ALGORITHM, encryption)) ++ continue; ++ + switch (encryption) + { + case ENCR_AES_CCM_ICV8: +@@ -690,6 +829,8 @@ static void proposal_add_supported_ike(private_proposal_t *this) + enumerator = lib->crypto->create_signer_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &integrity, &plugin_name)) + { ++ if (!fips_filter(PROTO_IKE, INTEGRITY_ALGORITHM, integrity)) ++ continue; + switch (integrity) + { + case AUTH_HMAC_SHA1_96: +@@ -710,6 +851,8 @@ static void proposal_add_supported_ike(private_proposal_t *this) + enumerator = lib->crypto->create_prf_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &prf, &plugin_name)) + { ++ if (!fips_filter(PROTO_IKE, PSEUDO_RANDOM_FUNCTION, prf)) ++ continue; + switch (prf) + { + case PRF_HMAC_SHA1: +@@ -730,6 +873,8 @@ static void proposal_add_supported_ike(private_proposal_t *this) + enumerator = lib->crypto->create_dh_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &group, &plugin_name)) + { ++ if (!fips_filter(PROTO_IKE, DIFFIE_HELLMAN_GROUP, group)) ++ continue; + switch (group) + { + case MODP_NULL: +@@ -776,31 +921,35 @@ proposal_t *proposal_create_default(protocol_id_t protocol) + { + private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0); + ++#define fips_add_algorithm(this, type, alg, len) \ ++ if (fips_filter(this->protocol, type, alg)) \ ++ add_algorithm(this, type, alg, len); + switch (protocol) + { + case PROTO_IKE: + proposal_add_supported_ike(this); + break; + case PROTO_ESP: +- add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128); +- add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192); +- add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256); +- add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0); +- add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256); +- add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); +- add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0); +- add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); +- add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); ++ fips_add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128); ++ fips_add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192); ++ fips_add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256); ++ fips_add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0); ++ fips_add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256); ++ fips_add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); ++ fips_add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0); ++ fips_add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); ++ fips_add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); + break; + case PROTO_AH: +- add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); +- add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0); +- add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); +- add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); ++ fips_add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); ++ fips_add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0); ++ fips_add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); ++ fips_add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); + break; + default: + break; + } ++#undef fips_add_algorithm + return &this->public; + } +