mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[master] Merge branch 'trac781'
Conflicts: configure.ac doc/Doxyfile src/lib/Makefile.am Also updated includes (because of the lib/util move)
This commit is contained in:
44
configure.ac
44
configure.ac
@@ -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
|
||||
|
11
doc/Doxyfile
11
doc/Doxyfile
@@ -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
|
||||
|
@@ -1,2 +1,3 @@
|
||||
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
|
||||
|
12
src/lib/cryptolink/Makefile.am
Normal file
12
src/lib/cryptolink/Makefile.am
Normal file
@@ -0,0 +1,12 @@
|
||||
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
|
237
src/lib/cryptolink/crypto_hmac.cc
Normal file
237
src/lib/cryptolink/crypto_hmac.cc
Normal file
@@ -0,0 +1,237 @@
|
||||
// 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
|
209
src/lib/cryptolink/crypto_hmac.h
Normal file
209
src/lib/cryptolink/crypto_hmac.h
Normal file
@@ -0,0 +1,209 @@
|
||||
// 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
|
||||
|
75
src/lib/cryptolink/cryptolink.cc
Normal file
75
src/lib/cryptolink/cryptolink.cc
Normal file
@@ -0,0 +1,75 @@
|
||||
// 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)
|
||||
{
|
||||
return (new HMAC(secret, secret_len, hash_algorithm));
|
||||
}
|
||||
|
||||
} // namespace cryptolink
|
||||
} // namespace isc
|
||||
|
204
src/lib/cryptolink/cryptolink.h
Normal file
204
src/lib/cryptolink/cryptolink.h
Normal file
@@ -0,0 +1,204 @@
|
||||
// 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.
|
||||
|
||||
#ifndef _ISC_CRYPTO_H
|
||||
#define _ISC_CRYPTO_H
|
||||
|
||||
#include <string>
|
||||
#include <util/buffer.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace isc {
|
||||
namespace cryptolink {
|
||||
|
||||
/// \brief Hash algorithm identifiers
|
||||
enum HashAlgorithm {
|
||||
MD5 = 0, ///< MD5
|
||||
SHA1 = 1, ///< SHA-1
|
||||
SHA256 = 2, ///< SHA-256
|
||||
UNKNOWN_HASH = 3 ///< This value can be used in conversion
|
||||
/// functions, to be returned when the
|
||||
/// input is unknown (but a value MUST be
|
||||
/// returned), for instance when the input
|
||||
/// is a Name or a string, and the return
|
||||
/// value is a HashAlgorithm.
|
||||
};
|
||||
|
||||
// Forward declaration for createHMAC()
|
||||
class HMAC;
|
||||
|
||||
/// General exception class that is the base for all crypto-related
|
||||
/// exceptions
|
||||
class CryptoLinkError : public Exception {
|
||||
public:
|
||||
CryptoLinkError(const char* file, size_t line, const char* what) :
|
||||
isc::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
/// This exception is thrown if there was a problem initializing the
|
||||
/// crypto library
|
||||
class InitializationError : public CryptoLinkError {
|
||||
public:
|
||||
InitializationError(const char* file, size_t line, const char* what) :
|
||||
CryptoLinkError(file, line, what) {}
|
||||
};
|
||||
|
||||
/// This exception is thrown when a cryptographic action is requested
|
||||
/// for an algorithm that is not supported by the underlying library.
|
||||
class UnsupportedAlgorithm : public CryptoLinkError {
|
||||
public:
|
||||
UnsupportedAlgorithm(const char* file, size_t line, const char* what) :
|
||||
CryptoLinkError(file, line, what) {}
|
||||
};
|
||||
|
||||
/// This exception is thrown when the underlying library could not
|
||||
/// handle the key data.
|
||||
class BadKey : public CryptoLinkError {
|
||||
public:
|
||||
BadKey(const char* file, size_t line, const char* what) :
|
||||
CryptoLinkError(file, line, what) {}
|
||||
};
|
||||
|
||||
/// This exception is raised when a general error that was not
|
||||
/// specifically caught is thrown by the underlying library. It
|
||||
/// is replaced by this one so as not have 'external' exceptions
|
||||
/// bubbling up
|
||||
class LibraryError : public CryptoLinkError {
|
||||
public:
|
||||
LibraryError(const char* file, size_t line, const char* what) :
|
||||
CryptoLinkError(file, line, what) {}
|
||||
};
|
||||
|
||||
/// Forward declaration for pimpl
|
||||
class CryptoLinkImpl;
|
||||
|
||||
/// \brief Singleton entry point and factory class
|
||||
///
|
||||
/// This is a singleton class that serves as the entry point to
|
||||
/// the underlying cryptography library, and as a factory for objects
|
||||
/// within the cryptolink library.
|
||||
///
|
||||
/// There is only one way to access it, through getCryptoLink(), which
|
||||
/// returns a reference to the initialized library. On the first call,
|
||||
/// it will be initialized automatically. You can however initialize it
|
||||
/// manually through a call to the initalize(), before your first call
|
||||
/// to getCryptoLink. Any subsequent call to initialize() will be a
|
||||
/// noop.
|
||||
///
|
||||
/// In order for the CryptoLink library to be sure that the underlying
|
||||
/// library has been initialized, and because we do not want to add
|
||||
/// such a check to every class and function within it, we have made
|
||||
/// the constructors of all classes within cryptolink private. This way
|
||||
/// a caller cannot instantiate an object before the library is
|
||||
/// initialized, but must use CryptoLink's create method (e.g.
|
||||
/// createHMAC()), which enforces (automatic) initialization.
|
||||
///
|
||||
/// In order for the CryptoLink class to be able to create objects that
|
||||
/// have private constructors, it is declared a friend class of these
|
||||
/// classes.
|
||||
///
|
||||
/// Since these factory functions return bare pointers, we also provide
|
||||
/// deleter functions for them (e.g. deleteHMAC()), so that a caller
|
||||
/// can use that to make sure it uses the correct delete operator (the
|
||||
/// one defined at compilation time of this library). A way to make
|
||||
/// sure you do not forget this, is to place the result of the create
|
||||
/// functions in a shared_ptr with the corresponding deleter function.
|
||||
///
|
||||
/// \note All other classes within cryptolink should have private
|
||||
/// constructors as well, and should have a factory function from
|
||||
/// CryptoLink, and a deleter function.
|
||||
///
|
||||
// Internal note: we can use this class later to initialize and manage
|
||||
// dynamic (PKCS#11) libs
|
||||
class CryptoLink : private boost::noncopyable {
|
||||
public:
|
||||
/// \brief Returns a reference to the singleton instance
|
||||
///
|
||||
/// If the library has not been initialized yet, it will be
|
||||
/// initialized with some default values.
|
||||
///
|
||||
/// Since this class is noncopyable, you must use the return
|
||||
/// value directly, or store it in a reference variable.
|
||||
///
|
||||
/// \exception InitializationError if initialization fails
|
||||
///
|
||||
/// \return Reference to the singleton instance
|
||||
static CryptoLink& getCryptoLink();
|
||||
|
||||
/// \brief Initialize the library manually
|
||||
///
|
||||
/// If the library has already been initialized (either by a call
|
||||
/// to initialize() or automatically in getCryptoLink()), this
|
||||
/// function does nothing.
|
||||
///
|
||||
/// \note A call to initialize() is not strictly necessary with
|
||||
/// the current implementation.
|
||||
///
|
||||
/// \exception InitializationError if initialization fails
|
||||
///
|
||||
static void initialize();
|
||||
|
||||
/// \brief Factory function for HMAC objects
|
||||
///
|
||||
/// CryptoLink objects cannot be constructed directly. This
|
||||
/// function creates a new HMAC object usable for signing or
|
||||
/// verification.
|
||||
///
|
||||
/// The caller is responsible for deleting the object, and it is
|
||||
/// therefore highly recommended to place the return value of this
|
||||
/// function in a scoped_ptr or shared_ptr.
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// If you want to safely delete objects created with this method,
|
||||
/// you can use the function deleteHMAC() as defined in
|
||||
/// crypto_hmac.h
|
||||
///
|
||||
/// \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
|
||||
///
|
||||
/// \param secret The secret to sign with
|
||||
/// \param secret_len The length of the secret
|
||||
/// \param hash_algorithm The hash algorithm
|
||||
HMAC* createHMAC(const void* secret, size_t secret_len,
|
||||
const HashAlgorithm hash_algorithm);
|
||||
|
||||
private:
|
||||
// To enable us to use an optional explicit initialization call,
|
||||
// the 'real' instance getter is private
|
||||
static CryptoLink& getCryptoLinkInternal();
|
||||
|
||||
// To prevent people constructing their own, we make the constructor
|
||||
// private too.
|
||||
CryptoLink() : impl_(NULL) {}
|
||||
~CryptoLink();
|
||||
|
||||
CryptoLinkImpl* impl_;
|
||||
};
|
||||
|
||||
} // namespace cryptolink
|
||||
} // namespace isc
|
||||
|
||||
#endif // _ISC_CRYPTO_H
|
26
src/lib/cryptolink/tests/Makefile.am
Normal file
26
src/lib/cryptolink/tests/Makefile.am
Normal file
@@ -0,0 +1,26 @@
|
||||
SUBDIRS = .
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||
AM_CXXFLAGS = $(B10_CXXFLAGS)
|
||||
|
||||
if USE_STATIC_LINK
|
||||
AM_LDFLAGS = -static
|
||||
endif
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
||||
|
||||
TESTS =
|
||||
if HAVE_GTEST
|
||||
TESTS += run_unittests
|
||||
run_unittests_SOURCES = run_unittests.cc
|
||||
run_unittests_SOURCES += crypto_unittests.cc
|
||||
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||
run_unittests_LDADD = $(GTEST_LDADD)
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libcryptolink.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS = $(TESTS)
|
511
src/lib/cryptolink/tests/crypto_unittests.cc
Normal file
511
src/lib/cryptolink/tests/crypto_unittests.cc
Normal file
@@ -0,0 +1,511 @@
|
||||
// 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 <config.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cryptolink/cryptolink.h>
|
||||
#include <cryptolink/crypto_hmac.h>
|
||||
|
||||
#include <util/buffer.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
using namespace isc::util;
|
||||
using namespace isc::cryptolink;
|
||||
|
||||
namespace {
|
||||
void checkData(const uint8_t* data, const uint8_t* expected,
|
||||
size_t len) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
ASSERT_EQ(expected[i], data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void checkBuffer(const OutputBuffer& buf, const uint8_t* expected,
|
||||
size_t len)
|
||||
{
|
||||
ASSERT_EQ(len, buf.getLength());
|
||||
checkData(static_cast<const uint8_t*>(buf.getData()), expected,
|
||||
len);
|
||||
}
|
||||
|
||||
// Sign and verify with the convenience functions
|
||||
void doHMACTestConv(const std::string& data,
|
||||
const void* secret,
|
||||
size_t secret_len,
|
||||
const HashAlgorithm hash_algorithm,
|
||||
const uint8_t* expected_hmac,
|
||||
size_t hmac_len) {
|
||||
OutputBuffer data_buf(data.size());
|
||||
data_buf.writeData(data.c_str(), data.size());
|
||||
OutputBuffer hmac_sig(0);
|
||||
|
||||
// Sign it
|
||||
signHMAC(data_buf.getData(), data_buf.getLength(),
|
||||
secret, secret_len, hash_algorithm, hmac_sig, hmac_len);
|
||||
|
||||
// Check if the signature is what we expect
|
||||
checkBuffer(hmac_sig, expected_hmac, hmac_len);
|
||||
|
||||
// Check whether we can verify it ourselves
|
||||
EXPECT_TRUE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
|
||||
secret, secret_len, hash_algorithm,
|
||||
hmac_sig.getData(),
|
||||
hmac_sig.getLength()));
|
||||
|
||||
// Change the sig by flipping the first octet, and check
|
||||
// whether verification fails then
|
||||
hmac_sig.writeUint8At(~hmac_sig[0], 0);
|
||||
EXPECT_FALSE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
|
||||
secret, secret_len, hash_algorithm,
|
||||
hmac_sig.getData(),
|
||||
hmac_sig.getLength()));
|
||||
}
|
||||
|
||||
// Sign and verify with an instantiation of an HMAC object
|
||||
void doHMACTestDirect(const std::string& data,
|
||||
const void* secret,
|
||||
size_t secret_len,
|
||||
const HashAlgorithm hash_algorithm,
|
||||
const uint8_t* expected_hmac,
|
||||
size_t hmac_len) {
|
||||
OutputBuffer data_buf(data.size());
|
||||
data_buf.writeData(data.c_str(), data.size());
|
||||
OutputBuffer hmac_sig(1);
|
||||
CryptoLink& crypto = CryptoLink::getCryptoLink();
|
||||
|
||||
// Sign it
|
||||
boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
|
||||
secret_len,
|
||||
hash_algorithm),
|
||||
deleteHMAC);
|
||||
hmac_sign->update(data_buf.getData(), data_buf.getLength());
|
||||
hmac_sign->sign(hmac_sig, hmac_len);
|
||||
|
||||
// Check if the signature is what we expect
|
||||
checkBuffer(hmac_sig, expected_hmac, hmac_len);
|
||||
|
||||
// Check whether we can verify it ourselves
|
||||
boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
|
||||
secret_len,
|
||||
hash_algorithm),
|
||||
deleteHMAC);
|
||||
hmac_verify->update(data_buf.getData(), data_buf.getLength());
|
||||
EXPECT_TRUE(hmac_verify->verify(hmac_sig.getData(),
|
||||
hmac_sig.getLength()));
|
||||
|
||||
// Change the sig by flipping the first octet, and check
|
||||
// whether verification fails then
|
||||
hmac_sig.writeUint8At(~hmac_sig[0], 0);
|
||||
EXPECT_FALSE(hmac_verify->verify(hmac_sig.getData(),
|
||||
hmac_sig.getLength()));
|
||||
}
|
||||
|
||||
void doHMACTestVector(const std::string& data,
|
||||
const void* secret,
|
||||
size_t secret_len,
|
||||
const HashAlgorithm hash_algorithm,
|
||||
const uint8_t* expected_hmac,
|
||||
size_t hmac_len) {
|
||||
CryptoLink& crypto = CryptoLink::getCryptoLink();
|
||||
boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
|
||||
secret_len,
|
||||
hash_algorithm),
|
||||
deleteHMAC);
|
||||
hmac_sign->update(data.c_str(), data.size());
|
||||
std::vector<uint8_t> sig = hmac_sign->sign(hmac_len);
|
||||
ASSERT_EQ(hmac_len, sig.size());
|
||||
checkData(&sig[0], expected_hmac, hmac_len);
|
||||
|
||||
boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
|
||||
secret_len,
|
||||
hash_algorithm),
|
||||
deleteHMAC);
|
||||
hmac_verify->update(data.c_str(), data.size());
|
||||
EXPECT_TRUE(hmac_verify->verify(&sig[0], sig.size()));
|
||||
|
||||
sig[0] = ~sig[0];
|
||||
EXPECT_FALSE(hmac_verify->verify(&sig[0], sig.size()));
|
||||
}
|
||||
|
||||
void doHMACTestArray(const std::string& data,
|
||||
const void* secret,
|
||||
size_t secret_len,
|
||||
const HashAlgorithm hash_algorithm,
|
||||
const uint8_t* expected_hmac,
|
||||
size_t hmac_len) {
|
||||
CryptoLink& crypto = CryptoLink::getCryptoLink();
|
||||
boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
|
||||
secret_len,
|
||||
hash_algorithm),
|
||||
deleteHMAC);
|
||||
hmac_sign->update(data.c_str(), data.size());
|
||||
|
||||
// note: this is not exception-safe, and can leak, but
|
||||
// if there is an unexpected exception in the code below we
|
||||
// have more important things to fix.
|
||||
uint8_t* sig = new uint8_t[hmac_len];
|
||||
|
||||
hmac_sign->sign(sig, hmac_len);
|
||||
checkData(sig, expected_hmac, hmac_len);
|
||||
|
||||
boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
|
||||
secret_len,
|
||||
hash_algorithm),
|
||||
deleteHMAC);
|
||||
hmac_verify->update(data.c_str(), data.size());
|
||||
EXPECT_TRUE(hmac_verify->verify(sig, hmac_len));
|
||||
|
||||
sig[0] = ~sig[0];
|
||||
EXPECT_FALSE(hmac_verify->verify(sig, hmac_len));
|
||||
|
||||
delete[] sig;
|
||||
}
|
||||
|
||||
void doHMACTest(const std::string& data,
|
||||
const void* secret,
|
||||
size_t secret_len,
|
||||
const HashAlgorithm hash_algorithm,
|
||||
const uint8_t* expected_hmac,
|
||||
size_t hmac_len) {
|
||||
doHMACTestConv(data, secret, secret_len, hash_algorithm,
|
||||
expected_hmac, hmac_len);
|
||||
doHMACTestDirect(data, secret, secret_len, hash_algorithm,
|
||||
expected_hmac, hmac_len);
|
||||
doHMACTestVector(data, secret, secret_len, hash_algorithm,
|
||||
expected_hmac, hmac_len);
|
||||
doHMACTestArray(data, secret, secret_len, hash_algorithm,
|
||||
expected_hmac, hmac_len);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Test values taken from RFC 2202
|
||||
//
|
||||
TEST(CryptoLinkTest, HMAC_MD5_RFC2202_SIGN) {
|
||||
const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b };
|
||||
const uint8_t hmac_expected[] = { 0x92, 0x94, 0x72, 0x7a, 0x36,
|
||||
0x38, 0xbb, 0x1c, 0x13, 0xf4,
|
||||
0x8e, 0xf8, 0x15, 0x8b, 0xfc,
|
||||
0x9d };
|
||||
doHMACTest("Hi There", secret, 16, MD5, hmac_expected, 16);
|
||||
|
||||
const uint8_t hmac_expected2[] = { 0x75, 0x0c, 0x78, 0x3e, 0x6a,
|
||||
0xb0, 0xb5, 0x03, 0xea, 0xa8,
|
||||
0x6e, 0x31, 0x0a, 0x5d, 0xb7,
|
||||
0x38 };
|
||||
doHMACTest("what do ya want for nothing?", "Jefe", 4, MD5,
|
||||
hmac_expected2, 16);
|
||||
|
||||
const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xaa };
|
||||
const uint8_t hmac_expected3[] = { 0x56, 0xbe, 0x34, 0x52, 0x1d,
|
||||
0x14, 0x4c, 0x88, 0xdb, 0xb8,
|
||||
0xc7, 0x33, 0xf0, 0xe8, 0xb3,
|
||||
0xf6};
|
||||
doHMACTest(std::string(50, 0xdd), secret3, 16, MD5, hmac_expected3, 16);
|
||||
|
||||
const std::string data4(50, 0xcd);
|
||||
const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
|
||||
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19 };
|
||||
const uint8_t hmac_expected4[] = { 0x69, 0x7e, 0xaf, 0x0a, 0xca,
|
||||
0x3a, 0x3a, 0xea, 0x3a, 0x75,
|
||||
0x16, 0x47, 0x46, 0xff, 0xaa,
|
||||
0x79 };
|
||||
doHMACTest(data4, secret4, 25, MD5, hmac_expected4, 16);
|
||||
|
||||
const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c };
|
||||
const uint8_t hmac_expected5[] = { 0x56, 0x46, 0x1e, 0xf2, 0x34,
|
||||
0x2e, 0xdc, 0x00, 0xf9, 0xba,
|
||||
0xb9, 0x95, 0x69, 0x0e, 0xfd,
|
||||
0x4c };
|
||||
doHMACTest("Test With Truncation", secret5, 16, MD5,
|
||||
hmac_expected5, 16);
|
||||
doHMACTest("Test With Truncation", secret5, 16, MD5,
|
||||
hmac_expected5, 12);
|
||||
|
||||
const uint8_t hmac_expected6[] = { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b,
|
||||
0xd7, 0xbf, 0x8f, 0x0b, 0x62,
|
||||
0xe6, 0xce, 0x61, 0xb9, 0xd0,
|
||||
0xcd };
|
||||
doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
|
||||
std::string(80, 0xaa).c_str(), 80, MD5, hmac_expected6, 16);
|
||||
|
||||
const uint8_t hmac_expected7[] = { 0x6f, 0x63, 0x0f, 0xad, 0x67,
|
||||
0xcd, 0xa0, 0xee, 0x1f, 0xb1,
|
||||
0xf5, 0x62, 0xdb, 0x3a, 0xa5,
|
||||
0x3e };
|
||||
doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
|
||||
"One Block-Size Data",
|
||||
std::string(80, 0xaa).c_str(), 80, MD5, hmac_expected7, 16);
|
||||
}
|
||||
|
||||
//
|
||||
// Test values taken from RFC 2202
|
||||
//
|
||||
TEST(CryptoLinkTest, HMAC_SHA1_RFC2202_SIGN) {
|
||||
const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
|
||||
const uint8_t hmac_expected[] = { 0xb6, 0x17, 0x31, 0x86, 0x55,
|
||||
0x05, 0x72, 0x64, 0xe2, 0x8b,
|
||||
0xc0, 0xb6, 0xfb, 0x37, 0x8c,
|
||||
0x8e, 0xf1, 0x46, 0xbe, 0x00 };
|
||||
doHMACTest("Hi There", secret, 20, SHA1, hmac_expected, 20);
|
||||
|
||||
const uint8_t hmac_expected2[] = { 0xef, 0xfc, 0xdf, 0x6a, 0xe5,
|
||||
0xeb, 0x2f, 0xa2, 0xd2, 0x74,
|
||||
0x16, 0xd5, 0xf1, 0x84, 0xdf,
|
||||
0x9c, 0x25, 0x9a, 0x7c, 0x79 };
|
||||
doHMACTest("what do ya want for nothing?", "Jefe", 4, SHA1,
|
||||
hmac_expected2, 20);
|
||||
|
||||
const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa };
|
||||
const uint8_t hmac_expected3[] = { 0x12, 0x5d, 0x73, 0x42, 0xb9,
|
||||
0xac, 0x11, 0xcd, 0x91, 0xa3,
|
||||
0x9a, 0xf4, 0x8a, 0xa1, 0x7b,
|
||||
0x4f, 0x63, 0xf1, 0x75, 0xd3 };
|
||||
doHMACTest(std::string(50, 0xdd), secret3, 20, SHA1, hmac_expected3, 20);
|
||||
|
||||
const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
|
||||
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19 };
|
||||
const uint8_t hmac_expected4[] = { 0x4c, 0x90, 0x07, 0xf4, 0x02,
|
||||
0x62, 0x50, 0xc6, 0xbc, 0x84,
|
||||
0x14, 0xf9, 0xbf, 0x50, 0xc8,
|
||||
0x6c, 0x2d, 0x72, 0x35, 0xda };
|
||||
doHMACTest(std::string(50, 0xcd), secret4, 25, SHA1, hmac_expected4, 20);
|
||||
|
||||
const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c };
|
||||
const uint8_t hmac_expected5[] = { 0x4c, 0x1a, 0x03, 0x42, 0x4b,
|
||||
0x55, 0xe0, 0x7f, 0xe7, 0xf2,
|
||||
0x7b, 0xe1, 0xd5, 0x8b, 0xb9,
|
||||
0x32, 0x4a, 0x9a, 0x5a, 0x04 };
|
||||
doHMACTest("Test With Truncation", secret5, 20, SHA1,
|
||||
hmac_expected5, 20);
|
||||
doHMACTest("Test With Truncation", secret5, 20, SHA1,
|
||||
hmac_expected5, 12);
|
||||
|
||||
const uint8_t hmac_expected6[] = { 0xaa, 0x4a, 0xe5, 0xe1, 0x52,
|
||||
0x72, 0xd0, 0x0e, 0x95, 0x70,
|
||||
0x56, 0x37, 0xce, 0x8a, 0x3b,
|
||||
0x55, 0xed, 0x40, 0x21, 0x12 };
|
||||
doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
|
||||
std::string(80, 0xaa).c_str(), 80, SHA1, hmac_expected6, 20);
|
||||
|
||||
const uint8_t hmac_expected7[] = { 0xe8, 0xe9, 0x9d, 0x0f, 0x45,
|
||||
0x23, 0x7d, 0x78, 0x6d, 0x6b,
|
||||
0xba, 0xa7, 0x96, 0x5c, 0x78,
|
||||
0x08, 0xbb, 0xff, 0x1a, 0x91 };
|
||||
doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
|
||||
"One Block-Size Data",
|
||||
std::string(80, 0xaa).c_str(), 80, SHA1, hmac_expected7, 20);
|
||||
}
|
||||
|
||||
//
|
||||
// Test values taken from RFC 4231
|
||||
//
|
||||
TEST(CryptoLinkTest, HMAC_SHA256_RFC2202_SIGN) {
|
||||
const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
|
||||
const uint8_t hmac_expected[] = { 0xb0, 0x34, 0x4c, 0x61, 0xd8,
|
||||
0xdb, 0x38, 0x53, 0x5c, 0xa8,
|
||||
0xaf, 0xce, 0xaf, 0x0b, 0xf1,
|
||||
0x2b, 0x88, 0x1d, 0xc2, 0x00,
|
||||
0xc9, 0x83, 0x3d, 0xa7, 0x26,
|
||||
0xe9, 0x37, 0x6c, 0x2e, 0x32,
|
||||
0xcf, 0xf7 };
|
||||
doHMACTest("Hi There", secret, 20, SHA256, hmac_expected, 32);
|
||||
|
||||
const uint8_t hmac_expected2[] = { 0x5b, 0xdc, 0xc1, 0x46, 0xbf,
|
||||
0x60, 0x75, 0x4e, 0x6a, 0x04,
|
||||
0x24, 0x26, 0x08, 0x95, 0x75,
|
||||
0xc7, 0x5a, 0x00, 0x3f, 0x08,
|
||||
0x9d, 0x27, 0x39, 0x83, 0x9d,
|
||||
0xec, 0x58, 0xb9, 0x64, 0xec,
|
||||
0x38, 0x43 };
|
||||
doHMACTest("what do ya want for nothing?", "Jefe", 4, SHA256,
|
||||
hmac_expected2, 32);
|
||||
|
||||
const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa };
|
||||
const uint8_t hmac_expected3[] = { 0x77, 0x3e, 0xa9, 0x1e, 0x36,
|
||||
0x80, 0x0e, 0x46, 0x85, 0x4d,
|
||||
0xb8, 0xeb, 0xd0, 0x91, 0x81,
|
||||
0xa7, 0x29, 0x59, 0x09, 0x8b,
|
||||
0x3e, 0xf8, 0xc1, 0x22, 0xd9,
|
||||
0x63, 0x55, 0x14, 0xce, 0xd5,
|
||||
0x65, 0xfe };
|
||||
doHMACTest(std::string(50, 0xdd), secret3, 20, SHA256, hmac_expected3, 32);
|
||||
|
||||
const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
|
||||
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19 };
|
||||
const uint8_t hmac_expected4[] = { 0x82, 0x55, 0x8a, 0x38, 0x9a,
|
||||
0x44, 0x3c, 0x0e, 0xa4, 0xcc,
|
||||
0x81, 0x98, 0x99, 0xf2, 0x08,
|
||||
0x3a, 0x85, 0xf0, 0xfa, 0xa3,
|
||||
0xe5, 0x78, 0xf8, 0x07, 0x7a,
|
||||
0x2e, 0x3f, 0xf4, 0x67, 0x29,
|
||||
0x66, 0x5b };
|
||||
doHMACTest(std::string(50, 0xcd), secret4, 25, SHA256, hmac_expected4, 32);
|
||||
|
||||
const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c };
|
||||
const uint8_t hmac_expected5[] = { 0xa3, 0xb6, 0x16, 0x74, 0x73,
|
||||
0x10, 0x0e, 0xe0, 0x6e, 0x0c,
|
||||
0x79, 0x6c, 0x29, 0x55, 0x55,
|
||||
0x2b };
|
||||
doHMACTest("Test With Truncation", secret5, 20, SHA256,
|
||||
hmac_expected5, 16);
|
||||
|
||||
const uint8_t hmac_expected6[] = { 0x60, 0xe4, 0x31, 0x59, 0x1e,
|
||||
0xe0, 0xb6, 0x7f, 0x0d, 0x8a,
|
||||
0x26, 0xaa, 0xcb, 0xf5, 0xb7,
|
||||
0x7f, 0x8e, 0x0b, 0xc6, 0x21,
|
||||
0x37, 0x28, 0xc5, 0x14, 0x05,
|
||||
0x46, 0x04, 0x0f, 0x0e, 0xe3,
|
||||
0x7f, 0x54 };
|
||||
doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
|
||||
std::string(131, 0xaa).c_str(), 131, SHA256, hmac_expected6, 32);
|
||||
|
||||
const uint8_t hmac_expected7[] = { 0x9b, 0x09, 0xff, 0xa7, 0x1b,
|
||||
0x94, 0x2f, 0xcb, 0x27, 0x63,
|
||||
0x5f, 0xbc, 0xd5, 0xb0, 0xe9,
|
||||
0x44, 0xbf, 0xdc, 0x63, 0x64,
|
||||
0x4f, 0x07, 0x13, 0x93, 0x8a,
|
||||
0x7f, 0x51, 0x53, 0x5c, 0x3a,
|
||||
0x35, 0xe2 };
|
||||
doHMACTest("This is a test using a larger than block-size key and a"
|
||||
" larger than block-size data. The key needs to be hashe"
|
||||
"d before being used by the HMAC algorithm.",
|
||||
std::string(131, 0xaa).c_str(), 131, SHA256, hmac_expected7, 32);
|
||||
}
|
||||
|
||||
namespace {
|
||||
size_t
|
||||
sigVectorLength(HashAlgorithm alg, size_t len) {
|
||||
boost::shared_ptr<HMAC> hmac_sign(
|
||||
CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
|
||||
deleteHMAC);
|
||||
hmac_sign->update("asdf", 4);
|
||||
const std::vector<uint8_t> sig = hmac_sign->sign(len);
|
||||
return (sig.size());
|
||||
}
|
||||
|
||||
size_t
|
||||
sigBufferLength(HashAlgorithm alg, size_t len) {
|
||||
boost::shared_ptr<HMAC> hmac_sign(
|
||||
CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
|
||||
deleteHMAC);
|
||||
hmac_sign->update("asdf", 4);
|
||||
OutputBuffer sig(0);
|
||||
hmac_sign->sign(sig, len);
|
||||
return (sig.getLength());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CryptoLinkTest, HMACSigLengthArgument) {
|
||||
std::vector<uint8_t> sig;
|
||||
|
||||
EXPECT_EQ(16, sigVectorLength(MD5, 0));
|
||||
EXPECT_EQ(8, sigVectorLength(MD5, 8));
|
||||
EXPECT_EQ(16, sigVectorLength(MD5, 16));
|
||||
EXPECT_EQ(16, sigVectorLength(MD5, 40));
|
||||
EXPECT_EQ(16, sigVectorLength(MD5, 2000));
|
||||
|
||||
EXPECT_EQ(20, sigBufferLength(SHA1, 0));
|
||||
EXPECT_EQ(8, sigBufferLength(SHA1, 8));
|
||||
EXPECT_EQ(20, sigBufferLength(SHA1, 20));
|
||||
EXPECT_EQ(20, sigBufferLength(SHA1, 40));
|
||||
EXPECT_EQ(20, sigBufferLength(SHA1, 2000));
|
||||
|
||||
EXPECT_EQ(32, sigBufferLength(SHA256, 0));
|
||||
EXPECT_EQ(8, sigBufferLength(SHA256, 8));
|
||||
EXPECT_EQ(32, sigBufferLength(SHA256, 32));
|
||||
EXPECT_EQ(32, sigBufferLength(SHA256, 40));
|
||||
EXPECT_EQ(32, sigBufferLength(SHA256, 3200));
|
||||
|
||||
EXPECT_EQ(16, sigBufferLength(MD5, 0));
|
||||
EXPECT_EQ(8, sigBufferLength(MD5, 8));
|
||||
EXPECT_EQ(16, sigBufferLength(MD5, 16));
|
||||
EXPECT_EQ(16, sigBufferLength(MD5, 40));
|
||||
EXPECT_EQ(16, sigBufferLength(MD5, 2000));
|
||||
|
||||
EXPECT_EQ(20, sigBufferLength(SHA1, 0));
|
||||
EXPECT_EQ(8, sigBufferLength(SHA1, 8));
|
||||
EXPECT_EQ(20, sigBufferLength(SHA1, 20));
|
||||
EXPECT_EQ(20, sigBufferLength(SHA1, 40));
|
||||
EXPECT_EQ(20, sigBufferLength(SHA1, 2000));
|
||||
|
||||
EXPECT_EQ(32, sigBufferLength(SHA256, 0));
|
||||
EXPECT_EQ(8, sigBufferLength(SHA256, 8));
|
||||
EXPECT_EQ(32, sigBufferLength(SHA256, 32));
|
||||
EXPECT_EQ(32, sigBufferLength(SHA256, 40));
|
||||
EXPECT_EQ(32, sigBufferLength(SHA256, 3200));
|
||||
}
|
||||
|
||||
TEST(CryptoLinkTest, BadKey) {
|
||||
OutputBuffer data_buf(0);
|
||||
OutputBuffer hmac_sig(0);
|
||||
CryptoLink& crypto = CryptoLink::getCryptoLink();
|
||||
|
||||
EXPECT_THROW(crypto.createHMAC(NULL, 0, MD5), BadKey);
|
||||
EXPECT_THROW(crypto.createHMAC(NULL, 0, UNKNOWN_HASH), UnsupportedAlgorithm);
|
||||
|
||||
EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
|
||||
NULL, 0, MD5, hmac_sig), BadKey);
|
||||
EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
|
||||
NULL, 0, UNKNOWN_HASH, hmac_sig),
|
||||
UnsupportedAlgorithm);
|
||||
|
||||
EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
|
||||
NULL, 0, MD5, hmac_sig.getData(),
|
||||
hmac_sig.getLength()), BadKey);
|
||||
EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
|
||||
NULL, 0, UNKNOWN_HASH, hmac_sig.getData(),
|
||||
hmac_sig.getLength()),
|
||||
UnsupportedAlgorithm);
|
||||
}
|
||||
|
||||
TEST(CryptoLinkTest, Singleton) {
|
||||
const CryptoLink& c1 = CryptoLink::getCryptoLink();
|
||||
const CryptoLink& c2 = CryptoLink::getCryptoLink();
|
||||
ASSERT_EQ(&c1, &c2);
|
||||
}
|
22
src/lib/cryptolink/tests/run_unittests.cc
Normal file
22
src/lib/cryptolink/tests/run_unittests.cc
Normal file
@@ -0,0 +1,22 @@
|
||||
// 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 <gtest/gtest.h>
|
||||
|
||||
int
|
||||
main(int argc, char* argv[]) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
return (RUN_ALL_TESTS());
|
||||
}
|
@@ -44,6 +44,28 @@ class TSIGKeyTest(unittest.TestCase):
|
||||
TSIGKey.HMACMD5_NAME,
|
||||
'should be binary') # signature mismatch
|
||||
|
||||
def test_str(self):
|
||||
k1 = TSIGKey('test.example:CwsLCwsLCwsLCwsLCwsLCw==:hmac-md5.sig-alg.reg.int')
|
||||
self.assertEqual(Name('test.example.'), k1.get_key_name())
|
||||
self.assertEqual(Name('hmac-md5.sig-alg.reg.int.'), k1.get_algorithm_name())
|
||||
self.assertEqual(b'\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b',
|
||||
k1.get_secret())
|
||||
self.assertEqual('test.example.:CwsLCwsLCwsLCwsLCwsLCw==:hmac-md5.sig-alg.reg.int.',
|
||||
k1.to_text())
|
||||
|
||||
self.assertRaises(InvalidParameter, TSIGKey,
|
||||
'test.example:CwsLCwsLCwsLCwsLCwsLCw==:unsupported')
|
||||
self.assertRaises(InvalidParameter, TSIGKey,
|
||||
'::')
|
||||
self.assertRaises(InvalidParameter, TSIGKey,
|
||||
'test.example:')
|
||||
self.assertRaises(InvalidParameter, TSIGKey,
|
||||
'test.example:%bad_base_64%')
|
||||
self.assertRaises(InvalidParameter, TSIGKey,
|
||||
'test.example:CwsLCwsLCwsLCwsLCwsLCw==:')
|
||||
self.assertRaises(InvalidParameter, TSIGKey,
|
||||
'test.:example:CwsLCwsLCwsLCwsLCwsLCw==')
|
||||
|
||||
class TSIGKeyRingTest(unittest.TestCase):
|
||||
key_name = Name('example.com')
|
||||
secret = b'someRandomData'
|
||||
|
@@ -55,6 +55,7 @@ void TSIGKey_destroy(s_TSIGKey* self);
|
||||
PyObject* TSIGKey_getKeyName(const s_TSIGKey* self);
|
||||
PyObject* TSIGKey_getAlgorithmName(const s_TSIGKey* self);
|
||||
PyObject* TSIGKey_getSecret(const s_TSIGKey* self);
|
||||
PyObject* TSIGKey_toText(const s_TSIGKey* self);
|
||||
|
||||
// This list contains the actual set of functions we have in
|
||||
// python. Each entry has
|
||||
@@ -72,6 +73,8 @@ PyMethodDef TSIGKey_methods[] = {
|
||||
{ "get_secret",
|
||||
reinterpret_cast<PyCFunction>(TSIGKey_getSecret), METH_NOARGS,
|
||||
"Return the value of the TSIG secret." },
|
||||
{ "to_text", reinterpret_cast<PyCFunction>(TSIGKey_toText), METH_NOARGS,
|
||||
"Returns the string representation (name:secret:algorithm)" },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
@@ -148,27 +151,33 @@ createNameObject(const Name& source) {
|
||||
|
||||
int
|
||||
TSIGKey_init(s_TSIGKey* self, PyObject* args) {
|
||||
const char* str;
|
||||
|
||||
const s_Name* key_name;
|
||||
const s_Name* algorithm_name;
|
||||
PyObject* bytes_obj;
|
||||
const char* secret;
|
||||
Py_ssize_t secret_len;
|
||||
|
||||
if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
|
||||
|
||||
try {
|
||||
if (PyArg_ParseTuple(args, "s", &str)) {
|
||||
self->tsigkey = new TSIGKey(str);
|
||||
return (0);
|
||||
} else if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
|
||||
&name_type, &algorithm_name, &bytes_obj) &&
|
||||
PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
|
||||
try {
|
||||
self->tsigkey = new TSIGKey(*key_name->name,
|
||||
*algorithm_name->name,
|
||||
secret, secret_len);
|
||||
} catch (const isc::InvalidParameter& ex) {
|
||||
PyErr_SetString(po_InvalidParameter, ex.what());
|
||||
return (-1);
|
||||
} catch (...) {
|
||||
PyErr_SetString(po_IscException, "Unexpected exception");
|
||||
return (-1);
|
||||
PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
|
||||
self->tsigkey = new TSIGKey(*key_name->name,
|
||||
*algorithm_name->name,
|
||||
secret, secret_len);
|
||||
return (0);
|
||||
}
|
||||
return (0);
|
||||
} catch (const isc::InvalidParameter& ex) {
|
||||
PyErr_SetString(po_InvalidParameter, ex.what());
|
||||
return (-1);
|
||||
} catch (...) {
|
||||
PyErr_SetString(po_IscException, "Unexpected exception");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
@@ -201,6 +210,11 @@ TSIGKey_getSecret(const s_TSIGKey* const self) {
|
||||
self->tsigkey->getSecretLength()));
|
||||
}
|
||||
|
||||
PyObject*
|
||||
TSIGKey_toText(const s_TSIGKey* self) {
|
||||
return (Py_BuildValue("s", self->tsigkey->toText().c_str()));
|
||||
}
|
||||
|
||||
// Module Initialization, all statics are initialized here
|
||||
bool
|
||||
initModulePart_TSIGKey(PyObject* mod) {
|
||||
|
@@ -227,4 +227,31 @@ TEST_F(TSIGKeyRingTest, findFromSome) {
|
||||
keyring.find(Name("noexist.example")).key);
|
||||
}
|
||||
|
||||
TEST(TSIGStringTest, TSIGKeyFromToString) {
|
||||
TSIGKey k1 = TSIGKey("test.example:MSG6Ng==:hmac-md5.sig-alg.reg.int");
|
||||
TSIGKey k2 = TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.");
|
||||
TSIGKey k3 = TSIGKey("test.example:MSG6Ng==");
|
||||
TSIGKey k4 = TSIGKey(Name("test.example."), Name("hmac-sha1."), NULL, 0);
|
||||
|
||||
EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
|
||||
k1.toText());
|
||||
EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
|
||||
k2.toText());
|
||||
EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
|
||||
k3.toText());
|
||||
EXPECT_EQ("test.example.::hmac-sha1.", k4.toText());
|
||||
|
||||
EXPECT_THROW(TSIGKey(""), isc::InvalidParameter);
|
||||
EXPECT_THROW(TSIGKey(":"), isc::InvalidParameter);
|
||||
EXPECT_THROW(TSIGKey("::"), isc::InvalidParameter);
|
||||
EXPECT_THROW(TSIGKey("..:aa:"), isc::InvalidParameter);
|
||||
EXPECT_THROW(TSIGKey("test.example:xxxx:"), isc::InvalidParameter);
|
||||
EXPECT_THROW(TSIGKey("test.example.::"), isc::InvalidParameter);
|
||||
EXPECT_THROW(TSIGKey("test.example.:"), isc::InvalidParameter);
|
||||
EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:"), isc::InvalidParameter);
|
||||
EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:unknown"), isc::InvalidParameter);
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // end namespace
|
||||
|
@@ -15,14 +15,26 @@
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
#include <cryptolink/cryptolink.h>
|
||||
|
||||
#include <dns/name.h>
|
||||
#include <util/encode/base64.h>
|
||||
#include <dns/tsigkey.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
bool isValidAlgorithmName(const isc::dns::Name& name) {
|
||||
return (name == isc::dns::TSIGKey::HMACMD5_NAME() ||
|
||||
name == isc::dns::TSIGKey::HMACSHA1_NAME() ||
|
||||
name == isc::dns::TSIGKey::HMACSHA256_NAME());
|
||||
}
|
||||
}
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
struct
|
||||
@@ -44,9 +56,7 @@ TSIGKey::TSIGKeyImpl {
|
||||
TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
|
||||
const void* secret, size_t secret_len) : impl_(NULL)
|
||||
{
|
||||
if (algorithm_name != HMACMD5_NAME() &&
|
||||
algorithm_name != HMACSHA1_NAME() &&
|
||||
algorithm_name != HMACSHA256_NAME()) {
|
||||
if (!isValidAlgorithmName(algorithm_name)) {
|
||||
isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
|
||||
algorithm_name);
|
||||
}
|
||||
@@ -59,6 +69,50 @@ TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
|
||||
impl_ = new TSIGKeyImpl(key_name, algorithm_name, secret, secret_len);
|
||||
}
|
||||
|
||||
TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) {
|
||||
try {
|
||||
istringstream iss(str);
|
||||
|
||||
string keyname_str;
|
||||
getline(iss, keyname_str, ':');
|
||||
if (iss.fail() || iss.bad() || iss.eof()) {
|
||||
isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
|
||||
}
|
||||
|
||||
string secret_str;
|
||||
getline(iss, secret_str, ':');
|
||||
if (iss.fail() || iss.bad()) {
|
||||
isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
|
||||
}
|
||||
|
||||
string algo_str;
|
||||
if (!iss.eof()) {
|
||||
getline(iss, algo_str);
|
||||
}
|
||||
if (iss.fail() || iss.bad()) {
|
||||
isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
|
||||
}
|
||||
|
||||
const Name algo_name(algo_str.empty() ? "hmac-md5.sig-alg.reg.int" :
|
||||
algo_str);
|
||||
if (!isValidAlgorithmName(algo_name)) {
|
||||
isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
|
||||
algo_name);
|
||||
}
|
||||
|
||||
vector<uint8_t> secret;
|
||||
isc::util::encode::decodeBase64(secret_str, secret);
|
||||
|
||||
impl_ = new TSIGKeyImpl(Name(keyname_str), algo_name, &secret[0],
|
||||
secret.size());
|
||||
} catch (const Exception& e) {
|
||||
// 'reduce' the several types of exceptions name parsing and
|
||||
// Base64 decoding can throw to just the InvalidParameter
|
||||
isc_throw(InvalidParameter, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TSIGKey::TSIGKey(const TSIGKey& source) : impl_(new TSIGKeyImpl(*source.impl_))
|
||||
{}
|
||||
|
||||
@@ -99,6 +153,17 @@ TSIGKey::getSecretLength() const {
|
||||
return (impl_->secret_.size());
|
||||
}
|
||||
|
||||
std::string
|
||||
TSIGKey::toText() const {
|
||||
const vector<uint8_t> secret_v(static_cast<const uint8_t*>(getSecret()),
|
||||
static_cast<const uint8_t*>(getSecret()) +
|
||||
getSecretLength());
|
||||
std::string secret_str = isc::util::encode::encodeBase64(secret_v);
|
||||
|
||||
return (getKeyName().toText() + ":" + secret_str + ":" +
|
||||
getAlgorithmName().toText());
|
||||
}
|
||||
|
||||
const
|
||||
Name& TSIGKey::HMACMD5_NAME() {
|
||||
static Name alg_name("hmac-md5.sig-alg.reg.int");
|
||||
|
@@ -90,6 +90,25 @@ public:
|
||||
TSIGKey(const Name& key_name, const Name& algorithm_name,
|
||||
const void* secret, size_t secret_len);
|
||||
|
||||
/// \brief Constructor from an input string
|
||||
///
|
||||
/// The string must be of the form:
|
||||
/// <name>:<secret>[:<algorithm>]
|
||||
/// Where <name> is a domain name for the key, <secret> is a
|
||||
/// base64 representation of the key secret, and the optional
|
||||
/// algorithm is an algorithm identifier as specified in RFC4635
|
||||
/// The default algorithm is hmac-md5.sig-alg.reg.int.
|
||||
///
|
||||
/// Since ':' is used as a separator here, it is not possible to
|
||||
/// use this constructor to create keys with a ':' character in
|
||||
/// their name.
|
||||
///
|
||||
/// \exception InvalidParameter exception if the input string is
|
||||
/// invalid.
|
||||
///
|
||||
/// \param str The string to make a TSIGKey from
|
||||
explicit TSIGKey(const std::string& str);
|
||||
|
||||
/// \brief The copy constructor.
|
||||
///
|
||||
/// It internally allocates a resource, and if it fails a corresponding
|
||||
@@ -139,6 +158,18 @@ public:
|
||||
const void* getSecret() const;
|
||||
//@}
|
||||
|
||||
/// \brief Converts the TSIGKey to a string value
|
||||
///
|
||||
/// The resulting string will be of the form
|
||||
/// name:secret:algorithm
|
||||
/// Where <name> is a domain name for the key, <secret> is a
|
||||
/// base64 representation of the key secret, and algorithm is
|
||||
/// an algorithm identifier as specified in RFC4635
|
||||
///
|
||||
/// \param key the TSIG key to convert
|
||||
/// \return The string representation of the given TSIGKey.
|
||||
std::string toText() const;
|
||||
|
||||
///
|
||||
/// \name Well known algorithm names as defined in RFC2845 and RFC4635.
|
||||
///
|
||||
|
Reference in New Issue
Block a user