mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-04 07:55:18 +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
|
fi
|
||||||
AC_SUBST(USE_LCOV)
|
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
|
# Configure Boost header path
|
||||||
#
|
#
|
||||||
@@ -673,11 +705,8 @@ AC_CONFIG_FILES([Makefile
|
|||||||
src/lib/config/Makefile
|
src/lib/config/Makefile
|
||||||
src/lib/config/tests/Makefile
|
src/lib/config/tests/Makefile
|
||||||
src/lib/config/tests/testdata/Makefile
|
src/lib/config/tests/testdata/Makefile
|
||||||
src/lib/util/Makefile
|
src/lib/cryptolink/Makefile
|
||||||
src/lib/util/io/Makefile
|
src/lib/cryptolink/tests/Makefile
|
||||||
src/lib/util/io/tests/Makefile
|
|
||||||
src/lib/util/unittests/Makefile
|
|
||||||
src/lib/util/tests/Makefile
|
|
||||||
src/lib/dns/Makefile
|
src/lib/dns/Makefile
|
||||||
src/lib/dns/tests/Makefile
|
src/lib/dns/tests/Makefile
|
||||||
src/lib/dns/tests/testdata/Makefile
|
src/lib/dns/tests/testdata/Makefile
|
||||||
@@ -702,6 +731,11 @@ AC_CONFIG_FILES([Makefile
|
|||||||
src/lib/cache/tests/Makefile
|
src/lib/cache/tests/Makefile
|
||||||
src/lib/server_common/Makefile
|
src/lib/server_common/Makefile
|
||||||
src/lib/server_common/tests/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/Makefile
|
||||||
tests/system/Makefile
|
tests/system/Makefile
|
||||||
tests/tools/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
|
# directories like "/usr/src/myproject". Separate the files or directories
|
||||||
# with spaces.
|
# with spaces.
|
||||||
|
|
||||||
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns \
|
INPUT = ../src/lib/cc ../src/lib/config \
|
||||||
../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth \
|
../src/lib/cryptolink ../src/lib/dns ../src/lib/datasrc \
|
||||||
../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ \
|
../src/bin/auth ../src/bin/resolver ../src/lib/bench \
|
||||||
../src/lib/nsas ../src/lib/testutils ../src/lib/cache \
|
../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas \
|
||||||
../src/lib/server_common/ ../src/bin/sockcreator/ ../src/lib/util/
|
../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
|
# 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
|
# 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 \
|
SUBDIRS = exceptions util cryptolink dns cc config python xfr bench \
|
||||||
asiodns nsas cache resolve testutils datasrc server_common
|
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,
|
TSIGKey.HMACMD5_NAME,
|
||||||
'should be binary') # signature mismatch
|
'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):
|
class TSIGKeyRingTest(unittest.TestCase):
|
||||||
key_name = Name('example.com')
|
key_name = Name('example.com')
|
||||||
secret = b'someRandomData'
|
secret = b'someRandomData'
|
||||||
|
@@ -55,6 +55,7 @@ void TSIGKey_destroy(s_TSIGKey* self);
|
|||||||
PyObject* TSIGKey_getKeyName(const s_TSIGKey* self);
|
PyObject* TSIGKey_getKeyName(const s_TSIGKey* self);
|
||||||
PyObject* TSIGKey_getAlgorithmName(const s_TSIGKey* self);
|
PyObject* TSIGKey_getAlgorithmName(const s_TSIGKey* self);
|
||||||
PyObject* TSIGKey_getSecret(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
|
// This list contains the actual set of functions we have in
|
||||||
// python. Each entry has
|
// python. Each entry has
|
||||||
@@ -72,6 +73,8 @@ PyMethodDef TSIGKey_methods[] = {
|
|||||||
{ "get_secret",
|
{ "get_secret",
|
||||||
reinterpret_cast<PyCFunction>(TSIGKey_getSecret), METH_NOARGS,
|
reinterpret_cast<PyCFunction>(TSIGKey_getSecret), METH_NOARGS,
|
||||||
"Return the value of the TSIG secret." },
|
"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 }
|
{ NULL, NULL, 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,27 +151,33 @@ createNameObject(const Name& source) {
|
|||||||
|
|
||||||
int
|
int
|
||||||
TSIGKey_init(s_TSIGKey* self, PyObject* args) {
|
TSIGKey_init(s_TSIGKey* self, PyObject* args) {
|
||||||
|
const char* str;
|
||||||
|
|
||||||
const s_Name* key_name;
|
const s_Name* key_name;
|
||||||
const s_Name* algorithm_name;
|
const s_Name* algorithm_name;
|
||||||
PyObject* bytes_obj;
|
PyObject* bytes_obj;
|
||||||
const char* secret;
|
const char* secret;
|
||||||
Py_ssize_t secret_len;
|
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) &&
|
&name_type, &algorithm_name, &bytes_obj) &&
|
||||||
PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
|
PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
|
||||||
try {
|
self->tsigkey = new TSIGKey(*key_name->name,
|
||||||
self->tsigkey = new TSIGKey(*key_name->name,
|
*algorithm_name->name,
|
||||||
*algorithm_name->name,
|
secret, secret_len);
|
||||||
secret, secret_len);
|
return (0);
|
||||||
} catch (const isc::InvalidParameter& ex) {
|
|
||||||
PyErr_SetString(po_InvalidParameter, ex.what());
|
|
||||||
return (-1);
|
|
||||||
} catch (...) {
|
|
||||||
PyErr_SetString(po_IscException, "Unexpected exception");
|
|
||||||
return (-1);
|
|
||||||
}
|
}
|
||||||
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();
|
PyErr_Clear();
|
||||||
@@ -201,6 +210,11 @@ TSIGKey_getSecret(const s_TSIGKey* const self) {
|
|||||||
self->tsigkey->getSecretLength()));
|
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
|
// Module Initialization, all statics are initialized here
|
||||||
bool
|
bool
|
||||||
initModulePart_TSIGKey(PyObject* mod) {
|
initModulePart_TSIGKey(PyObject* mod) {
|
||||||
|
@@ -227,4 +227,31 @@ TEST_F(TSIGKeyRingTest, findFromSome) {
|
|||||||
keyring.find(Name("noexist.example")).key);
|
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
|
} // end namespace
|
||||||
|
@@ -15,14 +15,26 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include <exceptions/exceptions.h>
|
#include <exceptions/exceptions.h>
|
||||||
|
|
||||||
|
#include <cryptolink/cryptolink.h>
|
||||||
|
|
||||||
#include <dns/name.h>
|
#include <dns/name.h>
|
||||||
|
#include <util/encode/base64.h>
|
||||||
#include <dns/tsigkey.h>
|
#include <dns/tsigkey.h>
|
||||||
|
|
||||||
using namespace std;
|
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 isc {
|
||||||
namespace dns {
|
namespace dns {
|
||||||
struct
|
struct
|
||||||
@@ -44,9 +56,7 @@ TSIGKey::TSIGKeyImpl {
|
|||||||
TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
|
TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
|
||||||
const void* secret, size_t secret_len) : impl_(NULL)
|
const void* secret, size_t secret_len) : impl_(NULL)
|
||||||
{
|
{
|
||||||
if (algorithm_name != HMACMD5_NAME() &&
|
if (!isValidAlgorithmName(algorithm_name)) {
|
||||||
algorithm_name != HMACSHA1_NAME() &&
|
|
||||||
algorithm_name != HMACSHA256_NAME()) {
|
|
||||||
isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
|
isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
|
||||||
algorithm_name);
|
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);
|
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_))
|
TSIGKey::TSIGKey(const TSIGKey& source) : impl_(new TSIGKeyImpl(*source.impl_))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -99,6 +153,17 @@ TSIGKey::getSecretLength() const {
|
|||||||
return (impl_->secret_.size());
|
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
|
const
|
||||||
Name& TSIGKey::HMACMD5_NAME() {
|
Name& TSIGKey::HMACMD5_NAME() {
|
||||||
static Name alg_name("hmac-md5.sig-alg.reg.int");
|
static Name alg_name("hmac-md5.sig-alg.reg.int");
|
||||||
|
@@ -90,6 +90,25 @@ public:
|
|||||||
TSIGKey(const Name& key_name, const Name& algorithm_name,
|
TSIGKey(const Name& key_name, const Name& algorithm_name,
|
||||||
const void* secret, size_t secret_len);
|
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.
|
/// \brief The copy constructor.
|
||||||
///
|
///
|
||||||
/// It internally allocates a resource, and if it fails a corresponding
|
/// It internally allocates a resource, and if it fails a corresponding
|
||||||
@@ -139,6 +158,18 @@ public:
|
|||||||
const void* getSecret() const;
|
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.
|
/// \name Well known algorithm names as defined in RFC2845 and RFC4635.
|
||||||
///
|
///
|
||||||
|
Reference in New Issue
Block a user