Commit 9df42279 authored by Jelte Jansen's avatar Jelte Jansen
Browse files

[master] Merge branch 'trac781'

Conflicts:
	configure.ac
	doc/Doxyfile
	src/lib/Makefile.am

Also updated includes (because of the lib/util move)
parents 4903de33 05c6223c
......@@ -374,6 +374,38 @@ if test "$lcov" != "no"; then
fi
AC_SUBST(USE_LCOV)
# Check for Botan
botan_path=""
AC_ARG_WITH([botan],
AC_HELP_STRING([--with-botan=PATH],
[specify exact directory of Botan library]),
[botan_path="$withval"])
# If not specificed, try some common paths
if test -z "$with_botan"; then
botandirs="/usr/local /usr/pkg /opt /opt/local /usr"
for d in $botandirs
do
if test -f $d/include/botan/botan.h; then
botan_path=$d
break
fi
done
fi
if test "${botan_path}" ; then
CPPFLAGS="$CPPFLAGS -I${botan_path}/include"
LDFLAGS="$LDFLAGS -L${botan_path}/lib -lbotan"
fi
AC_CHECK_HEADERS([botan/botan.h],,AC_MSG_ERROR([Missing required header files.]))
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <botan/botan.h>],
[using namespace Botan;
LibraryInitializer::initialize();
])],
[AC_MSG_RESULT([checking for Botan library... yes])],
[AC_MSG_RESULT([checking for Botan library... no])
AC_MSG_ERROR([Missing Botan library])]
)
#
# Configure Boost header path
#
......@@ -673,11 +705,8 @@ AC_CONFIG_FILES([Makefile
src/lib/config/Makefile
src/lib/config/tests/Makefile
src/lib/config/tests/testdata/Makefile
src/lib/util/Makefile
src/lib/util/io/Makefile
src/lib/util/io/tests/Makefile
src/lib/util/unittests/Makefile
src/lib/util/tests/Makefile
src/lib/cryptolink/Makefile
src/lib/cryptolink/tests/Makefile
src/lib/dns/Makefile
src/lib/dns/tests/Makefile
src/lib/dns/tests/testdata/Makefile
......@@ -702,6 +731,11 @@ AC_CONFIG_FILES([Makefile
src/lib/cache/tests/Makefile
src/lib/server_common/Makefile
src/lib/server_common/tests/Makefile
src/lib/util/Makefile
src/lib/util/io/Makefile
src/lib/util/io/tests/Makefile
src/lib/util/unittests/Makefile
src/lib/util/tests/Makefile
tests/Makefile
tests/system/Makefile
tests/tools/Makefile
......
......@@ -568,11 +568,12 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns \
../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth \
../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ \
../src/lib/nsas ../src/lib/testutils ../src/lib/cache \
../src/lib/server_common/ ../src/bin/sockcreator/ ../src/lib/util/
INPUT = ../src/lib/cc ../src/lib/config \
../src/lib/cryptolink ../src/lib/dns ../src/lib/datasrc \
../src/bin/auth ../src/bin/resolver ../src/lib/bench \
../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas \
../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
../src/bin/sockcreator/ ../src/lib/util/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
......
SUBDIRS = exceptions util dns cc config python xfr bench log asiolink \
asiodns nsas cache resolve testutils datasrc server_common
SUBDIRS = exceptions util cryptolink dns cc config python xfr bench \
log asiolink asiodns nsas cache resolve testutils datasrc \
server_common
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = libcryptolink.la
libcryptolink_la_SOURCES = cryptolink.h cryptolink.cc
libcryptolink_la_SOURCES += crypto_hmac.h crypto_hmac.cc
// Copyright (C) 2011 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 <cryptolink.h>
#include <cryptolink/crypto_hmac.h>
#include <boost/scoped_ptr.hpp>
#include <botan/botan.h>
#include <botan/hmac.h>
#include <botan/hash.h>
#include <botan/types.h>
namespace {
const char*
getBotanHashAlgorithmName(isc::cryptolink::HashAlgorithm algorithm) {
switch (algorithm) {
case isc::cryptolink::MD5:
return ("MD5");
break;
case isc::cryptolink::SHA1:
return ("SHA-1");
break;
case isc::cryptolink::SHA256:
return ("SHA-256");
break;
case isc::cryptolink::UNKNOWN_HASH:
return ("Unknown");
break;
}
// compiler should have prevented us to reach this, since we have
// no default. But we need a return value anyway
return ("Unknown");
}
} // local namespace
namespace isc {
namespace cryptolink {
class HMACImpl {
public:
explicit HMACImpl(const void* secret, size_t secret_len,
const HashAlgorithm hash_algorithm) {
Botan::HashFunction* hash;
try {
hash = Botan::get_hash(
getBotanHashAlgorithmName(hash_algorithm));
} catch (const Botan::Algorithm_Not_Found&) {
isc_throw(isc::cryptolink::UnsupportedAlgorithm,
"Unknown hash algorithm: " + hash_algorithm);
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
}
hmac_.reset(new Botan::HMAC::HMAC(hash));
// If the key length is larger than the block size, we hash the
// key itself first.
try {
if (secret_len > hash->HASH_BLOCK_SIZE) {
Botan::SecureVector<Botan::byte> hashed_key =
hash->process(static_cast<const Botan::byte*>(secret),
secret_len);
hmac_->set_key(hashed_key.begin(), hashed_key.size());
} else {
hmac_->set_key(static_cast<const Botan::byte*>(secret),
secret_len);
}
} catch (const Botan::Invalid_Key_Length& ikl) {
isc_throw(BadKey, ikl.what());
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
}
}
~HMACImpl() { }
size_t getOutputLength() const {
return (hmac_->OUTPUT_LENGTH);
}
void update(const void* data, const size_t len) {
try {
hmac_->update(static_cast<const Botan::byte*>(data), len);
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
}
}
void sign(isc::util::OutputBuffer& result, size_t len) {
try {
Botan::SecureVector<Botan::byte> b_result(hmac_->final());
if (len == 0 || len > b_result.size()) {
len = b_result.size();
}
result.writeData(b_result.begin(), len);
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
}
}
void sign(void* result, size_t len) {
try {
Botan::SecureVector<Botan::byte> b_result(hmac_->final());
size_t output_size = getOutputLength();
if (output_size > len) {
output_size = len;
}
memcpy(result, b_result.begin(), output_size);
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
}
}
std::vector<uint8_t> sign(size_t len) {
try {
Botan::SecureVector<Botan::byte> b_result(hmac_->final());
if (len == 0 || len > b_result.size()) {
return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
} else {
return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
}
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
}
}
bool verify(const void* sig, size_t len) {
// 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();
if (len == 0 || len > getOutputLength()) {
len = getOutputLength();
}
return (Botan::same_mem(&our_mac[0],
static_cast<const unsigned char*>(sig),
len));
} catch (const Botan::Exception& exc) {
isc_throw(isc::cryptolink::LibraryError, exc.what());
}
}
private:
boost::scoped_ptr<Botan::HMAC> hmac_;
};
HMAC::HMAC(const void* secret, size_t secret_length,
const HashAlgorithm hash_algorithm)
{
impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
}
HMAC::~HMAC() {
delete impl_;
}
size_t
HMAC::getOutputLength() const {
return (impl_->getOutputLength());
}
void
HMAC::update(const void* data, const size_t len) {
impl_->update(data, len);
}
void
HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
impl_->sign(result, len);
}
void
HMAC::sign(void* result, size_t len) {
impl_->sign(result, len);
}
std::vector<uint8_t>
HMAC::sign(size_t len) {
return impl_->sign(len);
}
bool
HMAC::verify(const void* sig, const size_t len) {
return (impl_->verify(sig, len));
}
void
signHMAC(const void* data, size_t data_len, const void* secret,
size_t secret_len, const HashAlgorithm hash_algorithm,
isc::util::OutputBuffer& result, size_t len)
{
boost::scoped_ptr<HMAC> hmac(
CryptoLink::getCryptoLink().createHMAC(secret,
secret_len,
hash_algorithm));
hmac->update(data, data_len);
hmac->sign(result, len);
}
bool
verifyHMAC(const void* data, const size_t data_len, const void* secret,
size_t secret_len, const HashAlgorithm hash_algorithm,
const void* sig, const size_t sig_len)
{
boost::scoped_ptr<HMAC> hmac(
CryptoLink::getCryptoLink().createHMAC(secret,
secret_len,
hash_algorithm));
hmac->update(data, data_len);
return (hmac->verify(sig, sig_len));
}
void
deleteHMAC(HMAC* hmac) {
delete hmac;
}
} // namespace cryptolink
} // namespace isc
// Copyright (C) 2011 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 <util/buffer.h>
#include <boost/noncopyable.hpp>
#include <cryptolink/cryptolink.h>
#ifndef _ISC_CRYPTO_HMAC_H
#define _ISC_CRYPTO_HMAC_H
namespace isc {
namespace cryptolink {
/// Forward declaration, pimpl style
class HMACImpl;
/// \brief HMAC support
///
/// This class is used to create and verify HMAC signatures. Instances
/// can be created with CryptoLink::createHMAC()
///
class HMAC : private boost::noncopyable {
private:
/// \brief Constructor from a secret and a hash algorithm
///
/// \exception UnsupportedAlgorithmException if the given algorithm
/// is unknown or not supported by the underlying library
/// \exception InvalidKeyLength if the given key secret_len is bad
/// \exception LibraryError if there was any unexpected exception
/// in the underlying library
///
/// Notes: if the secret is longer than the block size of its
/// algorithm, the constructor will run it through the hash
/// algorithm, and use the digest as the secret for this HMAC
/// operation
///
/// \param secret The secret to sign with
/// \param len The length of the secret
/// \param hash_algorithm The hash algorithm
HMAC(const void* secret, size_t secret_len,
const HashAlgorithm hash_algorithm);
friend HMAC* CryptoLink::createHMAC(const void*, size_t,
const HashAlgorithm);
public:
/// \brief Destructor
~HMAC();
/// \brief Returns the output size of the digest
///
/// \return output size of the digest
size_t getOutputLength() const;
/// \brief Add data to digest
///
/// \exception LibraryError if there was any unexpected exception
/// in the underlying library
///
/// \param data The data to add
/// \param len The size of the data
void update(const void* data, const size_t len);
/// \brief Calculate the final signature
///
/// The result will be appended to the given outputbuffer
///
/// \exception LibraryError if there was any unexpected exception
/// in the underlying library
///
/// \param result The OutputBuffer to append the result to
/// \param len The number of bytes from the result to copy. If this
/// value is smaller than the algorithms output size, the
/// result will be truncated. If this value is larger, or 0
/// (the default), it will be ignored
void sign(isc::util::OutputBuffer& result, size_t len = 0);
/// \brief Calculate the final signature
///
/// len bytes of data from the result will be copied to *result
/// If len is larger than the output size, only output_size bytes
/// will be copied. If it is smaller, the output will be truncated
///
/// \exception LibraryError if there was any unexpected exception
/// in the underlying library
///
/// At least len bytes of data must be available for writing at
/// result
void sign(void* result, size_t len);
/// \brief Calculate the final signatre
///
/// The result will be returned as a std::vector<uint8_t>
///
/// \exception LibraryError if there was any unexpected exception
/// in the underlying library
///
/// \param len The number of bytes from the result to copy. If this
/// value is smaller than the algorithms output size, the
/// result will be truncated. If this value is larger, or 0
/// (the default), it will be ignored
/// \return a vector containing the signature
std::vector<uint8_t> sign(size_t len = 0);
/// \brief Verify an existing signature
///
/// \exception LibraryError if there was any unexpected exception
/// in the underlying library
///
/// \param sig The signature to verify
/// \param len The length of the signature. If this is non-zero,
/// and smaller than the output length of the algorithm,
/// only len bytes will be checked
/// \return true if the signature is correct, false otherwise
bool verify(const void* sig, size_t len);
private:
HMACImpl* impl_;
};
/// \brief Create an HMAC signature for the given data
///
/// This is a convenience function that calculates the hmac signature,
/// given a fixed amount of data. Internally it does the same as
/// creating an HMAC object, feeding it the data, and calculating the
/// resulting signature.
///
/// \exception UnsupportedAlgorithm if the given algorithm is unknown
/// or not supported by the underlying library
/// \exception BadKey if the given key secret_len is bad
/// \exception LibraryError if there was any unexpected exception
/// in the underlying library
///
/// Notes: if the secret is longer than the block size of its
/// algorithm, the constructor will run it through the hash
/// algorithm, and use the digest as the secret for this HMAC
/// operation
///
/// \param data The data to sign
/// \param data_len The length of the data
/// \param secret The secret to sign with
/// \param secret_len The length of the secret
/// \param hash_algorithm The hash algorithm
/// \param result The signature will be appended to this buffer
/// \param len If this is non-zero and less than the output size,
/// the result will be truncated to len bytes
void signHMAC(const void* data,
const size_t data_len,
const void* secret,
size_t secret_len,
const HashAlgorithm hash_algorithm,
isc::util::OutputBuffer& result,
size_t len = 0);
/// \brief Verify an HMAC signature for the given data
///
/// This is a convenience function that verifies an hmac signature,
/// given a fixed amount of data. Internally it does the same as
/// creating an HMAC object, feeding it the data, and checking the
/// resulting signature.
///
/// \exception UnsupportedAlgorithm if the given algorithm is unknown
/// or not supported by the underlying library
/// \exception BadKey if the given key secret_len is bad
/// \exception LibraryError if there was any unexpected exception
/// in the underlying library
///
/// Notes: if the secret is longer than the block size of its
/// algorithm, the constructor will run it through the hash
/// algorithm, and use the digest as the secret for this HMAC
/// operation
///
/// \param data The data to verify
/// \param data_len The length of the data
/// \param secret The secret to sign with
/// \param secret_len The length of the secret
/// \param hash_algorithm The hash algorithm
/// \param sig The signature to verify
/// \param sig_len The length of the signature
/// \return True if the signature verifies, false if not
bool verifyHMAC(const void* data,
const size_t data_len,
const void* secret,
size_t secret_len,
const HashAlgorithm hash_algorithm,
const void* sig,
const size_t sig_len);
/// \brief Delete an HMAC object
void deleteHMAC(HMAC* hmac);
} // namespace cryptolink
} // namespace isc
#endif // __ISC_CRYPTO_HMAC
// Copyright (C) 2011 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 <cryptolink/cryptolink.h>
#include <cryptolink/crypto_hmac.h>
#include <botan/botan.h>
#include <boost/scoped_ptr.hpp>
using namespace std;
using namespace isc::util;
namespace isc {
namespace cryptolink {
// For Botan, we use the CryptoLink class object in RAII style
class CryptoLinkImpl {
private:
Botan::LibraryInitializer botan_init_;
};
CryptoLink::~CryptoLink() {
delete impl_;
}
CryptoLink&
CryptoLink::getCryptoLink() {
CryptoLink& c = getCryptoLinkInternal();
if (c.impl_ == NULL) {
c.initialize();
}
return (c);
}
CryptoLink&
CryptoLink::getCryptoLinkInternal() {
static CryptoLink instance;
return (instance);
}
void
CryptoLink::initialize() {
CryptoLink& c = getCryptoLinkInternal();
if (c.impl_ == NULL) {
try {
c.impl_ = new CryptoLinkImpl();
} catch (const Botan::Exception& ex) {
isc_throw(InitializationError, ex.what());
}
}
}
HMAC*
CryptoLink::createHMAC(const void* secret, size_t secret_len,
const HashAlgorithm hash_algorithm)
{