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

[master] Finished merge of trac3908 (port cryptolink fixes)

parents 0a8a121c 0c56e5ea
1189. [func] fdupont
Owing to API changes, crypto code now requires OpenSSL 1.0.1 or
later.
(Trac #3908, git ....)
1188. [doc] vlegout
Fixed several spelling mistakes.
(Github #32, d51c005519c4add6fd0c37bcd68b0fbe94941b2d)
(Github #32, git d51c005519c4add6fd0c37bcd68b0fbe94941b2d)
1187. [bug] marcin
DHCPv4 server allows for allocating multiple leases for the
......
......@@ -825,7 +825,7 @@ then
else
CRYPTO_NAME="OpenSSL"
DISABLED_CRYPTO="Botan"
CRYPTO_PACKAGE="openssl-1.0.0"
CRYPTO_PACKAGE="openssl-1.0.1"
AC_DEFINE_UNQUOTED([WITH_OPENSSL], [], [Compile with OpenSSL crypto])
AC_MSG_CHECKING(for OpenSSL library)
# from bind9
......@@ -848,18 +848,10 @@ else
fi
AC_MSG_RESULT(yes)
if test "${use_openssl}" = "/usr" ; then
CRYPTO_CFLAGS=""
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"
......@@ -884,6 +876,8 @@ else
esac
fi
dnl Determine the OpenSSL version
# Officially we support >= 1.0.1, 0.9.8 should fail the HMAC API,
# 1.0.0 could work but is not recommended.
AC_MSG_CHECKING([OpenSSL version])
cat > conftest.cpp << EOF
#include <openssl/opensslv.h>
......@@ -914,6 +908,18 @@ EOF
])],
[AC_MSG_RESULT([yes])],
[AC_MSG_ERROR([missing EVP entry for SHA-2])])
dnl Check HMAC API
AC_MSG_CHECKING([HMAC functions returning ints])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <openssl/hmac.h>],
[HMAC_CTX ctx, tmp;
int n = HMAC_Init(&ctx, NULL, 0, NULL);
n += HMAC_Update(&ctx, NULL, 0);
n += HMAC_CTX_copy(&tmp, &ctx);
n += HMAC_Final(&tmp, NULL, NULL);
])],
[AC_MSG_RESULT([yes])],
[AC_MSG_ERROR([HMAC functions return void: the OpenSSL version should be too old, please change for >= 1.0.1])])
LIBS=${LIBS_SAVED}
CPPFLAGS=${CPPFLAGS_SAVED}
fi
......
......@@ -120,9 +120,10 @@
</para>
</listitem>
<listitem>
<listitem>
<para>
Botan (version 1.8, 1.9 or 1.10) or OpenSSL (versions 1.0.*).</para>
Botan (at least version 1.8) or OpenSSL (at least version 1.0.1).
</para>
</listitem>
<listitem>
......
......@@ -55,13 +55,12 @@
<listitem>
<simpara>
Kea supports two cryptographic libraries: Botan and OpenSSL. Only one of
them is required to be installed during compilation. If using Botan, Kea
requires the Botan cryptographic library for C++ (<ulink
url="http://botan.randombit.net/"/>), version 1.8, 1.9 or 1.10. If
OpenSSL is used, (<ulink url="http://www.openssl.org/"/>), then Kea
requires the OpenSSL C++ library version 1.0.*. Support for later
versions of Botan and OpenSSL will be added in future releases of Kea.
Kea supports two crypto libraries: Botan and OpenSSL. Only one of them
is required to be installed during compilation. Kea uses the Botan
crypto library for C++ (<ulink url="http://botan.randombit.net/"/>),
version 1.8 or later. As an alternative to Botan, Kea can use the
OpenSSL crypto library (<ulink url="http://www.openssl.org/"/>),
version 1.0.1 or later.
</simpara>
</listitem>
......
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -56,7 +56,8 @@ public:
/// @brief Constructor for specific hash algorithm
///
/// @param hash_algorithm The hash algorithm
explicit HashImpl(const HashAlgorithm hash_algorithm) {
explicit HashImpl(const HashAlgorithm hash_algorithm)
: hash_algorithm_(hash_algorithm), hash_() {
Botan::HashFunction* hash;
try {
hash = Botan::get_hash(btn::getHashAlgorithmName(hash_algorithm));
......@@ -74,6 +75,11 @@ public:
/// @brief Destructor
~HashImpl() { }
/// @brief Returns the HashAlgorithm of the object
HashAlgorithm getHashAlgorithm() const {
return (hash_algorithm_);
}
/// @brief Returns the output size of the digest
///
/// @return output size of the digest
......@@ -149,7 +155,10 @@ public:
}
private:
/// \brief The protected pointer to the Botan HashFunction object
/// @brief The hash algorithm
HashAlgorithm hash_algorithm_;
/// @brief The protected pointer to the Botan HashFunction object
boost::scoped_ptr<Botan::HashFunction> hash_;
};
......@@ -162,6 +171,11 @@ Hash::~Hash() {
delete impl_;
}
HashAlgorithm
Hash::getHashAlgorithm() const {
return (impl_->getHashAlgorithm());
}
size_t
Hash::getOutputLength() const {
return (impl_->getOutputLength());
......
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -34,16 +34,17 @@ public:
/// @param secret_len The length of the secret
/// @param hash_algorithm The hash algorithm
explicit HMACImpl(const void* secret, size_t secret_len,
const HashAlgorithm hash_algorithm) {
const HashAlgorithm hash_algorithm)
: hash_algorithm_(hash_algorithm), hmac_() {
Botan::HashFunction* hash;
try {
hash = Botan::get_hash(btn::getHashAlgorithmName(hash_algorithm));
} catch (const Botan::Algorithm_Not_Found&) {
isc_throw(isc::cryptolink::UnsupportedAlgorithm,
isc_throw(UnsupportedAlgorithm,
"Unknown hash algorithm: " <<
static_cast<int>(hash_algorithm));
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
isc_throw(LibraryError, exc.what());
}
hmac_.reset(new Botan::HMAC(hash));
......@@ -79,7 +80,7 @@ public:
} catch (const Botan::Invalid_Key_Length& ikl) {
isc_throw(BadKey, ikl.what());
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
isc_throw(LibraryError, exc.what());
}
}
......@@ -87,6 +88,11 @@ public:
~HMACImpl() {
}
/// @brief Returns the HashAlgorithm of the object
HashAlgorithm getHashAlgorithm() const {
return (hash_algorithm_);
}
/// @brief Returns the output size of the digest
///
/// @return output size of the digest
......@@ -109,7 +115,7 @@ public:
try {
hmac_->update(static_cast<const Botan::byte*>(data), len);
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
isc_throw(LibraryError, exc.what());
}
}
......@@ -125,7 +131,7 @@ public:
}
result.writeData(b_result.begin(), len);
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
isc_throw(LibraryError, exc.what());
}
}
......@@ -141,7 +147,7 @@ public:
}
std::memcpy(result, b_result.begin(), output_size);
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
isc_throw(LibraryError, exc.what());
}
}
......@@ -157,7 +163,7 @@ public:
return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
}
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
isc_throw(LibraryError, exc.what());
}
}
......@@ -166,11 +172,10 @@ public:
///
/// See @ref isc::cryptolink::HMAC::verify() for details.
bool verify(const void* sig, size_t len) {
/// @todo Botan's verify_mac checks if len matches the output_length,
/// which causes it to fail for truncated signatures, so we do
/// the check ourselves
// Botan's verify_mac checks if len matches the output_length,
// which causes it to fail for truncated signatures, so we do
// the check ourselves
try {
Botan::SecureVector<Botan::byte> our_mac = hmac_->final();
size_t size = getOutputLength();
if (len < 10 || len < size / 2) {
return (false);
......@@ -178,17 +183,26 @@ public:
if (len > size) {
len = size;
}
return (Botan::same_mem(&our_mac[0],
if (digest_.empty()) {
digest_ = hmac_->final();
}
return (Botan::same_mem(&digest_[0],
static_cast<const unsigned char*>(sig),
len));
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
isc_throw(LibraryError, exc.what());
}
}
private:
/// \brief The protected pointer to the Botan HMAC object
/// @brief The hash algorithm
HashAlgorithm hash_algorithm_;
/// @brief The protected pointer to the Botan HMAC object
boost::scoped_ptr<Botan::HMAC> hmac_;
/// @brief The digest cache for multiple verify
Botan::SecureVector<Botan::byte> digest_;
};
HMAC::HMAC(const void* secret, size_t secret_length,
......@@ -201,6 +215,11 @@ HMAC::~HMAC() {
delete impl_;
}
HashAlgorithm
HMAC::getHashAlgorithm() const {
return (impl_->getHashAlgorithm());
}
size_t
HMAC::getOutputLength() const {
return (impl_->getOutputLength());
......
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -42,6 +42,11 @@ public:
/// \brief Destructor
~Hash();
/// \brief Returns the HashAlgorithm of the object
///
/// \return hash algorithm
HashAlgorithm getHashAlgorithm() const;
/// \brief Returns the output size of the digest
///
/// \return output size of the digest
......
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -52,6 +52,11 @@ public:
/// \brief Destructor
~HMAC();
/// \brief Returns the HashAlgorithm of the object
///
/// \return hash algorithm
HashAlgorithm getHashAlgorithm() const;
/// \brief Returns the output size of the digest
///
/// \return output size of the digest
......@@ -93,7 +98,7 @@ public:
/// result
void sign(void* result, size_t len);
/// \brief Calculate the final signatre
/// \brief Calculate the final signature
///
/// The result will be returned as a std::vector<uint8_t>
///
......@@ -115,7 +120,9 @@ public:
/// \param sig The signature to verify
/// \param len The length of the signature. If this is smaller
/// than the output length of the algorithm,
/// only len bytes will be checked
/// only len bytes will be checked. If this is
/// larger than the output length of the algorithm,
/// only output size bytes will be checked
/// \return true if the signature is correct, false otherwise
///
/// \note verify() does not destroy its context so it can be
......
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -26,19 +26,13 @@ public:
typedef typename std::vector<T>::const_iterator const_iterator;
explicit SecBuf() : vec_(std::vector<T>()) {}
explicit SecBuf() : vec_() {}
explicit SecBuf(size_t n, const T& value = T()) :
vec_(std::vector<T>(n, value))
{}
explicit SecBuf(size_t n, const T& value = T()) : vec_(n, value) {}
SecBuf(iterator first, iterator last) :
vec_(std::vector<T>(first, last))
{}
SecBuf(iterator first, iterator last) : vec_(first, last) {}
SecBuf(const_iterator first, const_iterator last) :
vec_(std::vector<T>(first, last))
{}
SecBuf(const_iterator first, const_iterator last) : vec_(first, last) {}
SecBuf(const std::vector<T>& x) : vec_(x) {}
......@@ -70,6 +64,11 @@ public:
vec_.resize(sz);
};
void clear() {
std::memset(&vec_[0], 0, vec_.capacity() * sizeof(T));
vec_.clear();
}
SecBuf& operator=(const SecBuf& x) {
if (&x != *this) {
vec_ = x.vec_;
......
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -54,7 +54,8 @@ public:
/// @brief Constructor for specific hash algorithm
///
/// @param hash_algorithm The hash algorithm
explicit HashImpl(const HashAlgorithm hash_algorithm) {
explicit HashImpl(const HashAlgorithm hash_algorithm)
: hash_algorithm_(hash_algorithm), md_() {
const EVP_MD* algo = ossl::getHashAlgorithm(hash_algorithm);
if (algo == 0) {
isc_throw(isc::cryptolink::UnsupportedAlgorithm,
......@@ -76,6 +77,11 @@ public:
}
}
/// @brief Returns the HashAlgorithm of the object
HashAlgorithm getHashAlgorithm() const {
return (hash_algorithm_);
}
/// @brief Returns the output size of the digest
///
/// @return output size of the digest
......@@ -130,6 +136,9 @@ public:
}
private:
/// @brief The hash algorithm
HashAlgorithm hash_algorithm_;
/// @brief The protected pointer to the OpenSSL EVP_MD_CTX structure
boost::scoped_ptr<EVP_MD_CTX> md_;
};
......@@ -143,6 +152,11 @@ Hash::~Hash() {
delete impl_;
}
HashAlgorithm
Hash::getHashAlgorithm() const {
return (impl_->getHashAlgorithm());
}
size_t
Hash::getOutputLength() const {
return (impl_->getOutputLength());
......
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -30,7 +30,8 @@ public:
/// @param secret_len The length of the secret
/// @param hash_algorithm The hash algorithm
explicit HMACImpl(const void* secret, size_t secret_len,
const HashAlgorithm hash_algorithm) {
const HashAlgorithm hash_algorithm)
: hash_algorithm_(hash_algorithm), md_() {
const EVP_MD* algo = ossl::getHashAlgorithm(hash_algorithm);
if (algo == 0) {
isc_throw(UnsupportedAlgorithm,
......@@ -44,9 +45,11 @@ public:
md_.reset(new HMAC_CTX);
HMAC_CTX_init(md_.get());
HMAC_Init_ex(md_.get(), secret,
static_cast<int>(secret_len),
algo, NULL);
if (!HMAC_Init_ex(md_.get(), secret,
static_cast<int>(secret_len),
algo, NULL)) {
isc_throw(LibraryError, "HMAC_Init_ex");
}
}
/// @brief Destructor
......@@ -56,13 +59,18 @@ public:
}
}
/// @brief Returns the HashAlgorithm of the object
HashAlgorithm getHashAlgorithm() const {
return (hash_algorithm_);
}
/// @brief Returns the output size of the digest
///
/// @return output size of the digest
size_t getOutputLength() const {
int size = HMAC_size(md_.get());
if (size < 0) {
isc_throw(isc::cryptolink::LibraryError, "EVP_MD_CTX_size");
isc_throw(LibraryError, "HMAC_size");
}
return (static_cast<size_t>(size));
}
......@@ -71,7 +79,11 @@ public:
///
/// See @ref isc::cryptolink::HMAC::update() for details.
void update(const void* data, const size_t len) {
HMAC_Update(md_.get(), static_cast<const unsigned char*>(data), len);
if (!HMAC_Update(md_.get(),
static_cast<const unsigned char*>(data),
len)) {
isc_throw(LibraryError, "HMAC_Update");
}
}
/// @brief Calculate the final signature
......@@ -80,7 +92,9 @@ public:
void sign(isc::util::OutputBuffer& result, size_t len) {
size_t size = getOutputLength();
ossl::SecBuf<unsigned char> digest(size);
HMAC_Final(md_.get(), &digest[0], NULL);
if (!HMAC_Final(md_.get(), &digest[0], NULL)) {
isc_throw(LibraryError, "HMAC_Final");
}
if (len > size) {
len = size;
}
......@@ -93,7 +107,9 @@ public:
void sign(void* result, size_t len) {
size_t size = getOutputLength();
ossl::SecBuf<unsigned char> digest(size);
HMAC_Final(md_.get(), &digest[0], NULL);
if (!HMAC_Final(md_.get(), &digest[0], NULL)) {
isc_throw(LibraryError, "HMAC_Final");
}
if (len > size) {
len = size;
}
......@@ -106,7 +122,9 @@ public:
std::vector<uint8_t> sign(size_t len) {
size_t size = getOutputLength();
ossl::SecBuf<unsigned char> digest(size);
HMAC_Final(md_.get(), &digest[0], NULL);
if (!HMAC_Final(md_.get(), &digest[0], NULL)) {
isc_throw(LibraryError, "HMAC_Final");
}
if (len < size) {
digest.resize(len);
}
......@@ -117,12 +135,23 @@ public:
///
/// See @ref isc::cryptolink::HMAC::verify() for details.
bool verify(const void* sig, size_t len) {
// Check the length
size_t size = getOutputLength();
if (len < 10 || len < size / 2) {
return (false);
}
// Get the digest from a copy of the context
HMAC_CTX tmp;
HMAC_CTX_init(&tmp);
if (!HMAC_CTX_copy(&tmp, md_.get())) {
isc_throw(LibraryError, "HMAC_CTX_copy");
}
ossl::SecBuf<unsigned char> digest(size);
HMAC_Final(md_.get(), &digest[0], NULL);
if (!HMAC_Final(&tmp, &digest[0], NULL)) {
HMAC_CTX_cleanup(&tmp);
isc_throw(LibraryError, "HMAC_Final");
}
HMAC_CTX_cleanup(&tmp);
if (len > size) {
len = size;
}
......@@ -130,6 +159,8 @@ public:
}
private:
/// @brief The hash algorithm
HashAlgorithm hash_algorithm_;
/// @brief The protected pointer to the OpenSSL HMAC_CTX structure
boost::scoped_ptr<HMAC_CTX> md_;
......@@ -145,6 +176,11 @@ HMAC::~HMAC() {
delete impl_;
}
HashAlgorithm
HMAC::getHashAlgorithm() const {
return (impl_->getHashAlgorithm());
}
size_t
HMAC::getOutputLength() const {
return (impl_->getOutputLength());
......
......@@ -23,6 +23,7 @@ run_unittests_SOURCES += hmac_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
......
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -518,6 +518,28 @@ TEST(HashTest, SHA512_RFC6234) {
SHA512, hash_expected4, 64);
}
namespace {
/// @brief Get the hash algorithm
/// @param alg Hash algorithm enum
/// @return Hash algorithm enum
HashAlgorithm
digestHashAlgorithm(HashAlgorithm alg) {
boost::shared_ptr<Hash> hash_digest(
CryptoLink::getCryptoLink().createHash(alg),
deleteHash);
return (hash_digest->getHashAlgorithm());
}
}
TEST(HashTest, HashAlgorithm) {
EXPECT_EQ(MD5, digestHashAlgorithm(MD5));
EXPECT_EQ(SHA1, digestHashAlgorithm(SHA1));
EXPECT_EQ(SHA256, digestHashAlgorithm(SHA256));
EXPECT_EQ(SHA224, digestHashAlgorithm(SHA224));
EXPECT_EQ(SHA384, digestHashAlgorithm(SHA384));
EXPECT_EQ(SHA512, digestHashAlgorithm(SHA512));
}
namespace {
/// @brief Compute the vector digest length
/// @param alg Hash algorithm enum
......
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -136,6 +136,12 @@ namespace {
hmac_sig.writeUint8At(~hmac_sig[0], 0);
EXPECT_FALSE(hmac_verify->verify(hmac_sig.getData(),
hmac_sig.getLength()));
// Restore the sig by flipping the first octet, and check
// whether verification succeeds then
hmac_sig.writeUint8At(~hmac_sig[0], 0);
EXPECT_TRUE(hmac_verify->verify(hmac_sig.getData(),
hmac_sig.getLength()));
}
/// @brief Sign and verify with vector representation of signature
......@@ -200,6 +206,9 @@ namespace {
sig[0] = ~sig[0];
EXPECT_FALSE(hmac_verify->verify(sig, hmac_len));
sig[0] = ~sig[0];
EXPECT_TRUE(hmac_verify->verify(sig, hmac_len));
delete[] sig;
}
......@@ -595,6 +604,28 @@ TEST(HMACTest, HMAC_SHA256_RFC2202_SIGN_TRUNCATED) {
hmac_expected5, 16);
}
namespace {
/// @brief Get the hash algorithm
/// @param alg Hash algorithm enum
/// @return Hash algorithm enum
HashAlgorithm
signHashAlgorithm(HashAlgorithm alg) {
boost::shared_ptr<HMAC> hmac_sign(
CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),