Commit 4b4110dd authored by Francis Dupont's avatar Francis Dupont

applied #2406: OpenSSL alternate crypto backend

parent 314c47ea
794. [func] fdupont
cryptolink: add OpenSSL crypto backend as an alternative to Botan
by specifying --with-openssl[=PATH] on the "configure" command
line. Add hash support to the cryptolink API and use it in DHCP
DDNS, removing the Botan dependency.
(Trac #2406, git xxx)
793. [func] tmark 793. [func] tmark
DHCP-DDNS: Implemented dynamic reconfiguration of the server, DHCP-DDNS: Implemented dynamic reconfiguration of the server,
triggered when the SIGHUP signal is received by the server's triggered when the SIGHUP signal is received by the server's
......
...@@ -7,6 +7,7 @@ USE_LCOV=@USE_LCOV@ ...@@ -7,6 +7,7 @@ USE_LCOV=@USE_LCOV@
LCOV=@LCOV@ LCOV=@LCOV@
GENHTML=@GENHTML@ GENHTML=@GENHTML@
DISTCHECK_GTEST_CONFIGURE_FLAG=@DISTCHECK_GTEST_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG=@DISTCHECK_GTEST_CONFIGURE_FLAG@
DISTCHECK_CRYPTO_CONFIGURE_FLAG=@DISTCHECK_CRYPTO_CONFIGURE_FLAG@
DISTCLEANFILES = config.report DISTCLEANFILES = config.report
...@@ -16,6 +17,9 @@ DISTCHECK_CONFIGURE_FLAGS = --disable-install-configurations ...@@ -16,6 +17,9 @@ DISTCHECK_CONFIGURE_FLAGS = --disable-install-configurations
# Use same --with-gtest flag if set # Use same --with-gtest flag if set
DISTCHECK_CONFIGURE_FLAGS += $(DISTCHECK_GTEST_CONFIGURE_FLAG) DISTCHECK_CONFIGURE_FLAGS += $(DISTCHECK_GTEST_CONFIGURE_FLAG)
# Keep the crypto backend config
DISTCHECK_CONFIGURE_FLAGS += $(DISTCHECK_CRYPTO_CONFIGURE_FLAG)
dist_doc_DATA = AUTHORS COPYING ChangeLog README dist_doc_DATA = AUTHORS COPYING ChangeLog README
.PHONY: check-valgrind check-valgrind-suppress .PHONY: check-valgrind check-valgrind-suppress
...@@ -73,12 +77,17 @@ report-cpp-coverage: ...@@ -73,12 +77,17 @@ report-cpp-coverage:
c++/4.4\*/ext/\* \ c++/4.4\*/ext/\* \
c++/4.4\*/\*-\*/bits/\* \ c++/4.4\*/\*-\*/bits/\* \
boost/\* \ boost/\* \
if HAVE_BOTAN
botan/\* \ botan/\* \
endif
ext/asio/\* \ ext/asio/\* \
ext/coroutine/\* \ ext/coroutine/\* \
gtest/\* \ gtest/\* \
log4cplus/\* \
include/\* \ include/\* \
log4cplus/\* \
if HAVE_OPENSSL
openssl/\* \
endif
tests/\* \ tests/\* \
unittests/\* \ unittests/\* \
\*_unittests.cc \ \*_unittests.cc \
......
...@@ -646,6 +646,13 @@ AC_DEFUN([ACX_CHECK_PROG_NONCACHE], [ ...@@ -646,6 +646,13 @@ AC_DEFUN([ACX_CHECK_PROG_NONCACHE], [
IFS="$IFS_SAVED" IFS="$IFS_SAVED"
]) ])
# Avoid checking Botan if OpenSSL is wanted
AC_ARG_WITH([openssl],
[AS_HELP_STRING([--with-openssl[[=PATH]]], [Enables OpenSSL,
location can be specified optionally])],
[use_openssl="$withval"],
[use_openssl="auto"])
# Botan helper test function # Botan helper test function
# Tries to compile a botan program, given the output of the given # Tries to compile a botan program, given the output of the given
# config tool # config tool
...@@ -661,12 +668,12 @@ AC_DEFUN([ACX_TRY_BOTAN_TOOL], [ ...@@ -661,12 +668,12 @@ AC_DEFUN([ACX_TRY_BOTAN_TOOL], [
AC_MSG_CHECKING([usability of ${TOOL} ${TOOL_ARG}]) AC_MSG_CHECKING([usability of ${TOOL} ${TOOL_ARG}])
if test "$BOTAN_TOOL" != "" ; then if test "$BOTAN_TOOL" != "" ; then
if test -x ${BOTAN_TOOL}; then if test -x ${BOTAN_TOOL}; then
BOTAN_LIBS=`$BOTAN_TOOL $TOOL_ARG --libs` CRYPTO_LIBS=`$BOTAN_TOOL $TOOL_ARG --libs`
LIBS_SAVED=${LIBS} LIBS_SAVED=${LIBS}
LIBS="$LIBS $BOTAN_LIBS" LIBS="$LIBS $CRYPTO_LIBS"
BOTAN_INCLUDES=`$BOTAN_TOOL $TOOL_ARG --cflags` CRYPTO_INCLUDES=`$BOTAN_TOOL $TOOL_ARG --cflags`
CPPFLAGS_SAVED=${CPPFLAGS} CPPFLAGS_SAVED=${CPPFLAGS}
CPPFLAGS="$BOTAN_INCLUDES $CPPFLAGS" CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS"
#AC_MSG_RESULT([found]) #AC_MSG_RESULT([found])
AC_LINK_IFELSE( AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <botan/botan.h> [AC_LANG_PROGRAM([#include <botan/botan.h>
...@@ -711,14 +718,18 @@ AC_DEFUN([ACX_TRY_BOTAN_TOOL], [ ...@@ -711,14 +718,18 @@ AC_DEFUN([ACX_TRY_BOTAN_TOOL], [
# against botan should neither -config scripts nor pkgconfig data exist). # against botan should neither -config scripts nor pkgconfig data exist).
# #
botan_config="yes" botan_config="yes"
if test "${use_openssl}" != "auto" -a "${use_openssl}" != "no" ; then
botan_config="no"
fi
AC_ARG_WITH([botan-config], AC_ARG_WITH([botan-config],
AC_HELP_STRING([--with-botan-config=PATH], AC_HELP_STRING([--with-botan-config=PATH],
[specify the path to the botan-config script]), [specify the path to the botan-config script]),
[botan_config="$withval"]) [botan_config="$withval"])
if test "${botan_config}" = "no" ; then if test "${botan_config}" = "no" ; then
AC_MSG_ERROR([Need botan for libcryptolink]) if test "${use_openssl}" = "no" ; then
fi AC_MSG_ERROR([Need Botan or OpenSSL for libcryptolink])
if test "${botan_config}" != "yes" ; then fi
elif test "${botan_config}" != "yes" ; then
if test -x "${botan_config}" ; then if test -x "${botan_config}" ; then
if test -d "${botan_config}" ; then if test -d "${botan_config}" ; then
AC_MSG_ERROR([${botan_config} is a directory]) AC_MSG_ERROR([${botan_config} is a directory])
...@@ -763,91 +774,101 @@ fi ...@@ -763,91 +774,101 @@ fi
if test "x${BOTAN_CONFIG}" != "x" if test "x${BOTAN_CONFIG}" != "x"
then then
BOTAN_LIBS=`${BOTAN_CONFIG} --libs` CRYPTO_LIBS=`${BOTAN_CONFIG} --libs`
BOTAN_INCLUDES=`${BOTAN_CONFIG} --cflags` CRYPTO_INCLUDES=`${BOTAN_CONFIG} --cflags`
# We expect botan-config --libs to contain -L<path_to_libbotan>, but # We expect botan-config --libs to contain -L<path_to_libbotan>, but
# this is not always the case. As a heuristics workaround we add # this is not always the case. As a heuristics workaround we add
# -L`botan-config --prefix/lib` in this case (if not present already). # -L`botan-config --prefix/lib` in this case (if not present already).
# Same for BOTAN_INCLUDES (but using include instead of lib) below. # Same for CRYPTO_INCLUDES (but using include instead of lib) below.
if [ ${BOTAN_CONFIG} --prefix >/dev/null 2>&1 ] ; then if [ ${BOTAN_CONFIG} --prefix >/dev/null 2>&1 ] ; then
echo ${BOTAN_LIBS} | grep -- -L > /dev/null || \ echo ${CRYPTO_LIBS} | grep -- -L > /dev/null || \
BOTAN_LIBS="-L`${BOTAN_CONFIG} --prefix`/lib ${BOTAN_LIBS}" CRYPTO_LIBS="-L`${BOTAN_CONFIG} --prefix`/lib ${CRYPTO_LIBS}"
echo ${BOTAN_INCLUDES} | grep -- -I > /dev/null || \ echo ${CRYPTO_INCLUDES} | grep -- -I > /dev/null || \
BOTAN_INCLUDES="-I`${BOTAN_CONFIG} --prefix`/include ${BOTAN_INCLUDES}" CRYPTO_INCLUDES="-I`${BOTAN_CONFIG} --prefix`/include ${CRYPTO_INCLUDES}"
fi fi
fi fi
dnl Determine the Botan version if test "x${CRYPTO_LIBS}" != "x"
AC_MSG_CHECKING([Botan version]) then
cat > conftest.cpp << EOF dnl Determine the Botan version
AC_MSG_CHECKING([Botan version])
cat > conftest.cpp << EOF
#include <botan/version.h> #include <botan/version.h>
AUTOCONF_BOTAN_VERSION=BOTAN_VERSION_MAJOR . BOTAN_VERSION_MINOR . BOTAN_VERSION_PATCH AUTOCONF_BOTAN_VERSION=BOTAN_VERSION_MAJOR . BOTAN_VERSION_MINOR . BOTAN_VERSION_PATCH
EOF EOF
BOTAN_VERSION=`$CPP $CPPFLAGS $BOTAN_INCLUDES conftest.cpp | grep '^AUTOCONF_BOTAN_VERSION=' | $SED -e 's/^AUTOCONF_BOTAN_VERSION=//' -e 's/[[ ]]//g' -e 's/"//g' 2> /dev/null` CRYPTO_VERSION=`$CPP $CPPFLAGS $CRYPTO_INCLUDES conftest.cpp | grep '^AUTOCONF_BOTAN_VERSION=' | $SED -e 's/^AUTOCONF_BOTAN_VERSION=//' -e 's/[[ ]]//g' -e 's/"//g' 2> /dev/null`
if test -z "$BOTAN_VERSION"; then if test -z "$CRYPTO_VERSION"; then
BOTAN_VERSION="unknown" CRYPTO_VERSION="unknown"
fi fi
$RM -f conftest.cpp $RM -f conftest.cpp
AC_MSG_RESULT([$BOTAN_VERSION]) AC_MSG_RESULT([$CRYPTO_VERSION])
# botan-config script (and the way we call pkg-config) returns -L and -l # botan-config script (and the way we call pkg-config) returns -L and -l
# as one string, but we need them in separate values # as one string, but we need them in separate values
BOTAN_LDFLAGS= CRYPTO_LDFLAGS=
BOTAN_NEWLIBS= for flag in ${CRYPTO_LIBS}; do
for flag in ${BOTAN_LIBS}; do CRYPTO_LDFLAGS="${CRYPTO_LDFLAGS} `echo $flag | ${SED} -ne '/^\(\-L\)/p'`"
BOTAN_LDFLAGS="${BOTAN_LDFLAGS} `echo $flag | ${SED} -ne '/^\(\-L\)/p'`" CRYPTO_LIBS="${CRYPTO_LIBS} `echo $flag | ${SED} -ne '/^\(\-l\)/p'`"
BOTAN_LIBS="${BOTAN_LIBS} `echo $flag | ${SED} -ne '/^\(\-l\)/p'`" done
done
# See crypto_rpath for some info on why we do this
# See python_rpath for some info on why we do this if test "x$ISC_RPATH_FLAG" != "x"; then
if test "x$ISC_RPATH_FLAG" != "x"; then CRYPTO_RPATH=
BOTAN_RPATH= for flag in ${CRYPTO_LIBS}; do
for flag in ${BOTAN_LIBS}; do CRYPTO_RPATH="${CRYPTO_RPATH} `echo $flag | ${SED} -ne "s/^\(\-L\)/${ISC_RPATH_FLAG}/p"`"
BOTAN_RPATH="${BOTAN_RPATH} `echo $flag | ${SED} -ne "s/^\(\-L\)/${ISC_RPATH_FLAG}/p"`" done
done # According to the libtool manual, it should be sufficient if we
AC_SUBST(BOTAN_RPATH) # specify the "-R libdir" in our wrapper library of botan (no other
# programs will need libbotan directly); "libdir" should be added to
# According to the libtool manual, it should be sufficient if we # the program's binary image. But we've seen in our build environments
# specify the "-R libdir" in our wrapper library of botan (no other # that (some versions of?) libtool doesn't propagate -R as documented,
# programs will need libbotan directly); "libdir" should be added to # and it caused a linker error at run time. To work around this, we
# the program's binary image. But we've seen in our build environments # also add the rpath to the global LDFLAGS.
# that (some versions of?) libtool doesn't propagate -R as documented, LDFLAGS="$CRYPTO_RPATH $LDFLAGS"
# and it caused a linker error at run time. To work around this, we fi
# also add the rpath to the global LDFLAGS.
LDFLAGS="$BOTAN_RPATH $LDFLAGS" # Even though chances are high we already performed a real compilation check
fi # in the search for the right (pkg)config data, we try again here, to
# be sure.
AC_SUBST(BOTAN_LDFLAGS) CPPFLAGS_SAVED=$CPPFLAGS
AC_SUBST(BOTAN_LIBS) CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS"
AC_SUBST(BOTAN_INCLUDES) LIBS_SAVED="$LIBS"
# Even though chances are high we already performed a real compilation check LIBS="$LIBS $CRYPTO_LIBS"
# in the search for the right (pkg)config data, we try again here, to
# be sure. # ac_header_preproc is an autoconf symbol (undocumented but stable) that
CPPFLAGS_SAVED=$CPPFLAGS # is set if the pre-processor phase passes. Thus by adding a custom
CPPFLAGS="$BOTAN_INCLUDES $CPPFLAGS" # failure handler we can detect the difference between a header not existing
LIBS_SAVED="$LIBS" # (or not even passing the pre-processor phase) and a header file resulting
LIBS="$LIBS $BOTAN_LIBS" # in compilation failures.
AC_CHECK_HEADERS([botan/botan.h],,[
# ac_header_preproc is an autoconf symbol (undocumented but stable) that CRYPTO_INCLUDES=""
# is set if the pre-processor phase passes. Thus by adding a custom CRYPTO_LIBS=""
# failure handler we can detect the difference between a header not existing CRYPTO_LDFLAGS=""
# (or not even passing the pre-processor phase) and a header file resulting CRYPTO_RPATH=""
# in compilation failures.
AC_CHECK_HEADERS([botan/botan.h],,[
if test "x$ac_header_preproc" = "xyes"; then if test "x$ac_header_preproc" = "xyes"; then
AC_MSG_ERROR([ AC_MSG_RESULT([
botan/botan.h was found but is unusable. The most common cause of this problem botan/botan.h was found but is unusable. The most common cause of this problem
is attempting to use an updated C++ compiler with older C++ libraries, such as is attempting to use an updated C++ compiler with older C++ libraries, such as
the version of Botan that comes with your distribution. If you have updated the version of Botan that comes with your distribution. If you have updated
your C++ compiler we highly recommend that you use support libraries such as your C++ compiler we highly recommend that you use support libraries such as
Boost and Botan that were compiled with the same compiler version.]) Boost and Botan that were compiled with the same compiler version.])
else else
AC_MSG_ERROR([Missing required header files.]) AC_MSG_RESULT([Missing required header files.])
fi] fi]
) )
AC_LINK_IFELSE( CPPFLAGS=$CPPFLAGS_SAVED
LIBS=$LIBS_SAVED
fi
if test "x${CRYPTO_LIBS}" != "x"
then
CPPFLAGS_SAVED=$CPPFLAGS
CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS"
LIBS_SAVED="$LIBS"
LIBS="$LIBS $CRYPTO_LIBS"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <botan/botan.h> [AC_LANG_PROGRAM([#include <botan/botan.h>
#include <botan/hash.h> #include <botan/hash.h>
], ],
...@@ -857,14 +878,116 @@ AC_LINK_IFELSE( ...@@ -857,14 +878,116 @@ AC_LINK_IFELSE(
])], ])],
[AC_MSG_RESULT([checking for Botan library... yes])], [AC_MSG_RESULT([checking for Botan library... yes])],
[AC_MSG_RESULT([checking for Botan library... no]) [AC_MSG_RESULT([checking for Botan library... no])
AC_MSG_ERROR([Needs Botan library 1.8 or higher. On some systems, CRYPTO_INCLUDES=""
CRYPTO_LIBS=""
CRYPTO_LDFLAGS=""
CRYPTO_RPATH=""
AC_MSG_RESULT([Needs Botan library 1.8 or higher. On some systems,
the botan package has a few missing dependencies (libbz2 and the botan package has a few missing dependencies (libbz2 and
libgmp), if libbotan has been installed and you see this error, libgmp), if libbotan has been installed and you see this message,
try upgrading to a higher version of botan or installing libbz2 try upgrading to a higher version of botan or installing libbz2
and libgmp.])] and libgmp.])]
) )
CPPFLAGS=$CPPFLAGS_SAVED CPPFLAGS=$CPPFLAGS_SAVED
LIBS=$LIBS_SAVED LIBS=$LIBS_SAVED
fi
if test "x${CRYPTO_LIBS}" != "x"
then
CRYPTO_NAME="Botan"
DISABLED_CRYPTO="OpenSSL"
CRYPTO_PACKAGE="botan-1.8"
CRYPTO_CFLAGS=""
DISTCHECK_CRYPTO_CONFIGURE_FLAG="--with-botan=$botan_config"
AC_DEFINE_UNQUOTED([WITH_BOTAN], [], [Compile with Botan crypto])
else
CRYPTO_NAME="OpenSSL"
DISABLED_CRYPTO="Botan"
CRYPTO_PACKAGE="openssl-1.0.0"
AC_DEFINE_UNQUOTED([WITH_OPENSSL], [], [Compile with OpenSSL crypto])
AC_MSG_CHECKING(for OpenSSL library)
# from bind9
if test "${use_openssl}" = "auto" ; then
use_openssl="yes"
fi
if test "${use_openssl}" = "yes" ; then
for d in /usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw; do
if test -f $d/include/openssl/opensslv.h; then
use_openssl=$d; break
fi
done
fi
if test "${use_openssl}" = "yes" ; then
AC_MSG_ERROR([OpenSSL auto detection failed])
fi
if ! test -f "${use_openssl}"/include/openssl/opensslv.h ; then
AC_MSG_ERROR([OpenSSL not found at ${use_openssl}])
fi
AC_MSG_RESULT(yes)
if test "${use_openssl}" = "/usr" ; then
CRYPTO_INCLUDES=""
CRYPTO_LIBS="-lcrypto"
DISTCHECK_CRYPTO_CONFIGURE_FLAG="--with-openssl"
case "$host" in
*-apple-darwin*)
# Starting with OSX 10.7 (Lion) OpenSSL is deprecated
CRYPTO_CFLAGS="-Wno-deprecated-declarations"
;;
*)
CRYPTO_CFLAGS=""
;;
esac
else
CRYPTO_CFLAGS=""
CRYPTO_INCLUDES="-I${use_openssl}/include"
DISTCHECK_CRYPTO_CONFIGURE_FLAG="--with-openssl=${use_openssl}"
case $host in
*-solaris*)
CRYPTO_LIBS="-L${use_openssl}/lib -R${use_openssl}/lib -lcrypto"
;;
*-hp-hpux*)
CRYPTO_LIBS="-L${use_openssl}/lib -Wl,+b: -lcrypto"
;;
*-apple-darwin*)
if test -f "${use_openssl}/lib/libcrypto.dylib" ; then
CRYPTO_LIBS="-L${use_openssl}/lib -lcrypto"
else
CRYPTO_LIBS="${use_openssl}/lib/libcrypto.a"
fi
;;
*)
CRYPTO_LIBS="-L${use_openssl}/lib -lcrypto"
;;
esac
fi
dnl Determine the OpenSSL version
AC_MSG_CHECKING([OpenSSL version])
cat > conftest.cpp << EOF
#include <openssl/opensslv.h>
AUTOCONF_OPENSSL_VERSION=OPENSSL_VERSION_TEXT
EOF
CRYPTO_VERSION=`$CPP $CPPFLAGS $CRYPTO_INCLUDES conftest.cpp | grep '^AUTOCONF_OPENSSL_VERSION=' | $SED -e 's/^AUTOCONF_OPENSSL_VERSION=//' -e 's/"//g' 2> /dev/null`
if test -z "$CRYPTO_VERSION" ; then
CRYPTO_VERSION="unknown"
fi
$RM -f conftest.cpp
AC_MSG_RESULT([$CRYPTO_VERSION])
#CRYPTO_LDFLAGS="-ldl"
CRYPTO_LDFLAGS=""
CRYPTO_RPATH=""
fi
AM_CONDITIONAL(HAVE_BOTAN, test "$CRYPTO_NAME" = "Botan")
AM_CONDITIONAL(HAVE_OPENSSL, test "$CRYPTO_NAME" = "OpenSSL")
AC_SUBST(CRYPTO_INCLUDES)
AC_SUBST(CRYPTO_CFLAGS)
AC_SUBST(CRYPTO_LIBS)
AC_SUBST(CRYPTO_LDFLAGS)
AC_SUBST(CRYPTO_PACKAGE)
AC_SUBST(CRYPTO_RPATH)
AC_SUBST(DISTCHECK_CRYPTO_CONFIGURE_FLAG)
# Check for MySql. The path to the mysql_config program is given with # Check for MySql. The path to the mysql_config program is given with
# the --with-mysql-config (default to /usr/bin/mysql-config). By default, # the --with-mysql-config (default to /usr/bin/mysql-config). By default,
...@@ -1653,11 +1776,14 @@ Boost: ...@@ -1653,11 +1776,14 @@ Boost:
BOOST_VERSION: ${BOOST_VERSION} BOOST_VERSION: ${BOOST_VERSION}
BOOST_INCLUDES: ${BOOST_INCLUDES} BOOST_INCLUDES: ${BOOST_INCLUDES}
Botan: ${CRYPTO_NAME}:
BOTAN_VERSION: ${BOTAN_VERSION} CRYPTO_VERSION: ${CRYPTO_VERSION}
BOTAN_INCLUDES: ${BOTAN_INCLUDES} CRYPTO_CFLAGS: ${CRYPTO_CFLAGS}
BOTAN_LDFLAGS: ${BOTAN_LDFLAGS} CRYPTO_INCLUDES: ${CRYPTO_INCLUDES}
BOTAN_LIBS: ${BOTAN_LIBS} CRYPTO_LDFLAGS: ${CRYPTO_LDFLAGS}
CRYPTO_LIBS: ${CRYPTO_LIBS}
${DISABLED_CRYPTO}: no
Log4cplus: Log4cplus:
LOG4CPLUS_VERSION: ${LOG4CPLUS_VERSION} LOG4CPLUS_VERSION: ${LOG4CPLUS_VERSION}
......
...@@ -6,6 +6,6 @@ includedir=@includedir@ ...@@ -6,6 +6,6 @@ includedir=@includedir@
Name: dns++ Name: dns++
Description: BIND 10 DNS library Description: BIND 10 DNS library
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Requires: botan-1.8 Requires: @CRYPTO_PACKAGE@
Cflags: -I${includedir}/@PACKAGE_NAME@ Cflags: -I${includedir}/@PACKAGE_NAME@
Libs: -L${libdir} -lb10-dns++ -lb10-cryptolink -lb10-util -lb10-exceptions -lm Libs: -L${libdir} -lb10-dns++ -lb10-cryptolink -lb10-util -lb10-exceptions -lm
...@@ -138,9 +138,13 @@ ...@@ -138,9 +138,13 @@
</para> </para>
<para> <para>
Kea uses the Botan crypto library for C++ Kea supports two crypto libraries: Botan and OpenSSL. Only one
(<ulink url="http://botan.randombit.net/"/>). of them is required during compilation. Kea uses the Botan crypto
It requires at least Botan version 1.8. library for C++ (<ulink url="http://botan.randombit.net/"/>).
It requires at least Botan version 1.8. As an alternative to Botan,
Kea can use the OpenSSL crypto library
(<ulink url="http://www.openssl.org/"/>).
It requires a version with SHA-2 support.
</para> </para>
<para> <para>
...@@ -546,7 +550,7 @@ $ <userinput>./configure</userinput></screen> ...@@ -546,7 +550,7 @@ $ <userinput>./configure</userinput></screen>
<para> <para>
To build Kea, also install the Botan (at least version To build Kea, also install the Botan (at least version
1.8) and the log4cplus (at least version 1.0.3) 1.8) or OpenSSL, and the log4cplus (at least version 1.0.3)
development include headers. development include headers.
</para> </para>
...@@ -696,6 +700,17 @@ as a dependency earlier --> ...@@ -696,6 +700,17 @@ as a dependency earlier -->
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>--with-openssl</term>
<listitem>
<simpara>Replace Botan by OpenSSL for the crypto library.
The default is to try to find a working Botan then
OpenSSL only if not found.
<!-- missing -with-botan-config -->
</simpara>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term>--without-werror</term> <term>--without-werror</term>
<listitem> <listitem>
......
...@@ -52,9 +52,16 @@ b10-cmdctl: cmdctl.py $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py $(CERTFILE ...@@ -52,9 +52,16 @@ b10-cmdctl: cmdctl.py $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py $(CERTFILE
$(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" cmdctl.py >$@ $(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" cmdctl.py >$@
chmod a+x $@ chmod a+x $@
b10_certgen_SOURCES = b10-certgen.cc if HAVE_BOTAN
b10_certgen_CXXFLAGS = $(BOTAN_INCLUDES) b10_certgen_SOURCES = botan-certgen.cc
b10_certgen_LDFLAGS = $(BOTAN_LIBS) EXTRA_DIST += openssl-certgen.cc
endif
if HAVE_OPENSSL
b10_certgen_SOURCES = openssl-certgen.cc
EXTRA_DIST += botan-certgen.cc
endif
b10_certgen_CXXFLAGS = $(CRYPTO_CFLAGS) $(CRYPTO_INCLUDES)
b10_certgen_LDFLAGS = $(CRYPTO_LIBS)
# Generate the initial certificates immediately # Generate the initial certificates immediately
cmdctl-keyfile.pem: b10-certgen cmdctl-keyfile.pem: b10-certgen
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <cstring>
#include <iostream>
#include <fstream>
#include <memory>
#include <getopt.h>
// For cleaner 'does not exist or is not readable' output than
// openssl provides
#include <unistd.h>
#include <errno.h>
// This is a simple tool that creates a self-signed PEM certificate
// for use with BIND 10. It creates a simple certificate for initial
// setup. Currently, all values are hardcoded defaults. For future
// versions, we may want to add more options for administrators.
// It will create a PEM file containing a certificate with the following
// values:
// common name: localhost
// organization: BIND10
// country code: US
// Additional error return codes; these are specifically
// chosen to be distinct from validation error codes as
// provided by OpenSSL. Their main use is to distinguish
// error cases in the unit tests.
const int DECODING_ERROR = 100;
const int BAD_OPTIONS = 101;
const int READ_ERROR = 102;
const int WRITE_ERROR = 103;
const int UNKNOWN_ERROR = 104;
const int NO_SUCH_FILE = 105;
const int FILE_PERMISSION_ERROR = 106;
void
usage() {
std::cout << "Usage: b10-certgen [OPTION]..." << std::endl;
std::cout << "Validate, create, or update a self-signed certificate for "
"use with b10-cmdctl" << std::endl;
std::cout << "" << std::endl;
std::cout << "Options:" << std::endl;
std::cout << "-c, --certfile=FILE\t\tfile to read or store the certificate"
<< std::endl;
std::cout << "-f, --force\t\t\toverwrite existing certificate even if it"
<< std::endl <<"\t\t\t\tis valid" << std::endl;
std::cout << "-h, --help\t\t\tshow this help" << std::endl;
std::cout << "-k, --keyfile=FILE\t\tfile to store the generated private key"
<< std::endl;
std::cout << "-w, --write\t\t\tcreate a new certificate if the given file"
<< std::endl << "\t\t\t\tdoes not exist, or if is is not valid"
<< std::endl;
std::cout << "-q, --quiet\t\t\tprint no output when creating or validating"
<< std::endl;
}
/// \brief Returns true if the given file exists
///
/// \param filename The file to check
/// \return true if file exists
bool
fileExists(const std::string& filename) {
return (access(filename.c_str(), F_OK) == 0);
}
/// \brief Returns true if the given file exists and is readable
///
/// \param filename The file to check
/// \return true if file exists and is readable
bool
fileIsReadable(const std::string& filename) {
return (access(filename.c_str(), R_OK) == 0);
}
/// \brief Returns true if the given file exists and is writable
///
/// \param filename The file to check
/// \return true if file exists and is writable
bool
fileIsWritable(const std::string& filename) {
return (access(filename.c_str(), W_OK) == 0);
}
class CertificateTool {
public:
CertificateTool(bool quiet) : quiet_(quiet) {}
int
createKeyAndCertificate(const std::string& key_file_name,
const std::string& cert_file_name) {
// Create and store a private key
print("Creating key file " + key_file_name);
RSA* rsa = RSA_generate_key(2048, 65537UL, NULL, NULL);
std::ofstream key_file(key_file_name.c_str());
if (!key_file.good()) {
print(std::string("Error writing to ") + key_file_name +
": " + std::strerror(errno));
return (WRITE_ERROR);
}
BIO* key_mem = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(key_mem, rsa, NULL, NULL, 0, NULL, NULL);
char* p;
long len = BIO_get_mem_data(key_mem, &p);
key_file.write(p, (unsigned) len);
BIO_free(key_mem);
if (!key_file.good()) {
print(std::string("Error writing to ") + key_file_name +
": " + std::strerror(errno));
return (WRITE_ERROR);
}
key_file.close();
// Certificate options, currently hardcoded.
// For a future version we may want to make these
// settable.
X509* cert = X509_new();
X509_set_version(cert, 2);
BIGNUM* serial = BN_new();
BN_pseudo_rand(serial, 64, 0, 0);
BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(cert));
BN_free(serial);
X509_NAME* name = X509_get_subject_name(cert);
std::string cn("localhost");
X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
(unsigned char*) cn.c_str(), cn.size(),
-1, 0);
std::string org("UNKNOWN");
X509_NAME_add_entry_by_NID(name, NID_organizationName, MBSTRING_ASC,
(unsigned char*) org.c_str(), org.size(),
-1, 0);
std::string cc("XX");
X509_NAME_add_entry_by_NID(name, NID_countryName, MBSTRING_ASC,
(unsigned char*) cc.c_str(), cc.size(),
-1, 0);
X509_set_issuer_name(cert, name);