BIND 10 trac2402, updated. f3b5c8f5def1beedec7a6905dfa9bf34a3f609c7 [trac2402] first attempt
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Oct 25 08:20:45 UTC 2012
The branch, trac2402 has been updated
via f3b5c8f5def1beedec7a6905dfa9bf34a3f609c7 (commit)
from c4690c43b4856170b4da2c789d1605d5430b7cb8 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit f3b5c8f5def1beedec7a6905dfa9bf34a3f609c7
Author: Francis Dupont <fdupont at isc.org>
Date: Thu Oct 25 04:02:01 2012 +0200
[trac2402] first attempt
-----------------------------------------------------------------------
Summary of changes:
src/bin/auth/auth_srv.cc | 1 +
src/bin/auth/tests/auth_srv_unittest.cc | 15 +-
src/bin/ddns/ddns.py.in | 1 +
src/bin/ddns/tests/ddns_test.py | 5 +-
src/bin/xfrin/tests/xfrin_test.py | 18 +-
src/bin/xfrin/xfrin.py.in | 3 +-
src/bin/xfrout/tests/xfrout_test.py.in | 4 +-
src/bin/xfrout/xfrout.py.in | 7 +-
src/lib/cryptolink/crypto_hmac.cc | 31 +++-
src/lib/cryptolink/crypto_hmac.h | 2 +
src/lib/cryptolink/cryptolink.cc | 3 +-
src/lib/cryptolink/cryptolink.h | 16 ++
src/lib/cryptolink/tests/crypto_unittests.cc | 45 ++++-
src/lib/dns/python/pydnspp.cc | 5 +
src/lib/dns/python/tests/message_python_test.py | 25 +--
src/lib/dns/python/tests/tsig_python_test.py | 112 ++++++++-----
src/lib/dns/python/tsig_python.cc | 38 ++++-
src/lib/dns/tests/message_unittest.cc | 28 ++--
src/lib/dns/tests/tsig_unittest.cc | 200 ++++++++++++++---------
src/lib/dns/tsig.cc | 55 +++++--
src/lib/dns/tsig.h | 23 ++-
src/lib/python/isc/ddns/tests/session_tests.py | 2 +-
src/lib/python/isc/testutils/tsigctx_mock.py | 4 +-
23 files changed, 452 insertions(+), 191 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index 157ae03..ab123b3 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -544,6 +544,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
// The keyring can be null if we're in test
if (impl_->keyring_ != NULL && tsig_record != NULL) {
tsig_context.reset(new TSIGContext(tsig_record->getName(),
+ isc::cryptolink::Verify,
tsig_record->getRdata().
getAlgorithm(),
**impl_->keyring_));
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index d498d9d..dbf4bc0 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -304,7 +304,7 @@ TEST_F(AuthSrvTest, AXFRSuccess) {
// not be able to verify it, returning BADKEY
TEST_F(AuthSrvTest, TSIGSignedBadKey) {
TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
- TSIGContext context(key);
+ TSIGContext context(key, isc::cryptolink::Sign);
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Name("version.bind"), RRClass::CH(),
RRType::TXT());
@@ -338,7 +338,7 @@ TEST_F(AuthSrvTest, TSIGSignedBadKey) {
// (with the same name). It should return BADSIG
TEST_F(AuthSrvTest, TSIGBadSig) {
TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
- TSIGContext context(key);
+ TSIGContext context(key, isc::cryptolink::Sign);
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Name("version.bind"), RRClass::CH(),
RRType::TXT());
@@ -374,7 +374,7 @@ TEST_F(AuthSrvTest, TSIGBadSig) {
// else.
TEST_F(AuthSrvTest, TSIGCheckFirst) {
TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
- TSIGContext context(key);
+ TSIGContext context(key, isc::cryptolink::Sign);
// Pass a wrong opcode there. The server shouldn't know what to do
// about it.
UnitTestUtil::createRequestMessage(request_message, Opcode::RESERVED14(),
@@ -780,11 +780,11 @@ TEST_F(AuthSrvTest, TSIGSigned) {
// Prepare key, the client message, etc
updateBuiltin(server);
const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
- TSIGContext context(key);
+ TSIGContext context_sign(key, isc::cryptolink::Sign);
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Name("VERSION.BIND."), RRClass::CH(),
RRType::TXT());
- createRequestPacket(request_message, IPPROTO_UDP, &context);
+ createRequestPacket(request_message, IPPROTO_UDP, &context_sign);
// Run the message through the server
boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
@@ -804,8 +804,9 @@ TEST_F(AuthSrvTest, TSIGSigned) {
const TSIGRecord* tsig = m.getTSIGRecord();
ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
- TSIGError error(context.verify(tsig, response_obuffer->getData(),
- response_obuffer->getLength()));
+ TSIGContext context_verify(context_sign, isc::cryptolink::Verify);
+ TSIGError error(context_verify.verify(tsig, response_obuffer->getData(),
+ response_obuffer->getLength()));
EXPECT_EQ(TSIGError::NOERROR(), error) <<
"The server signed the response, but it doesn't seem to be valid";
diff --git a/src/bin/ddns/ddns.py.in b/src/bin/ddns/ddns.py.in
index eaeb06c..335f78f 100755
--- a/src/bin/ddns/ddns.py.in
+++ b/src/bin/ddns/ddns.py.in
@@ -425,6 +425,7 @@ class DDNSServer:
if tsig_record is None:
return None
tsig_ctx = TSIGContext(tsig_record.get_name(),
+ TSIGContext.VERIFY,
tsig_record.get_rdata().get_algorithm(),
isc.server_common.tsig_keyring.get_keyring())
tsig_error = tsig_ctx.verify(tsig_record, req_data)
diff --git a/src/bin/ddns/tests/ddns_test.py b/src/bin/ddns/tests/ddns_test.py
index 0f5ca9b..c4d3558 100755
--- a/src/bin/ddns/tests/ddns_test.py
+++ b/src/bin/ddns/tests/ddns_test.py
@@ -976,7 +976,10 @@ class TestDDNSSession(unittest.TestCase):
server_addr = TEST_SERVER6 if ipv6 else TEST_SERVER4
client_addr = TEST_CLIENT6 if ipv6 else TEST_CLIENT4
- tsig = TSIGContext(tsig_key) if tsig_key is not None else None
+ if tsig_key is None:
+ tsig = None
+ else:
+ tsig = TSIGContext(tsig_key, TSIGContext.SIGN)
rcode = Rcode.NOERROR() if result == UPDATE_SUCCESS else Rcode.REFUSED()
has_response = (result != UPDATE_DROP)
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index 7b9100e..4a4709d 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -569,7 +569,7 @@ class TestXfrinIXFRAdd(TestXfrinState):
# SOA RR whose serial is the current one means we are going to a new
# difference, starting with removing that SOA.
self.conn._diff.add_data(self.ns_rrset) # put some dummy change
- self.conn._tsig_ctx = MockTSIGContext(TSIG_KEY)
+ self.conn._tsig_ctx = MockTSIGContext(TSIG_KEY, TSIGContext.VERIFY)
self.conn._tsig_ctx.last_has_signature = lambda: False
# First, push a starting SOA inside. This should be OK, nothing checked
# yet.
@@ -748,13 +748,15 @@ class TestXfrinConnection(unittest.TestCase):
# a valid XFR messages will follow.
verify_ctx = None
+ tsig_ctx = None
if self.soa_response_params['tsig']:
# xfrin (currently) always uses TCP. strip off the length field.
query_data = self.conn.query_data[2:]
query_message = Message(Message.PARSE)
query_message.from_wire(query_data)
- verify_ctx = TSIGContext(TSIG_KEY)
+ verify_ctx = TSIGContext(TSIG_KEY, TSIGContext.VERIFY)
verify_ctx.verify(query_message.get_tsig_record(), query_data)
+ tsig_ctx=TSIGContext(verify_ctx, TSIGContext.SIGN)
self.conn.reply_data = self.conn.create_response_data(
bad_qid=self.soa_response_params['bad_qid'],
@@ -764,7 +766,7 @@ class TestXfrinConnection(unittest.TestCase):
questions=self.soa_response_params['questions'],
answers=self.soa_response_params['answers'],
authorities=self.soa_response_params['authorities'],
- tsig_ctx=verify_ctx)
+ tsig_ctx=tsig_ctx)
if self.soa_response_params['axfr_after_soa'] != None:
self.conn.response_generator = \
self.soa_response_params['axfr_after_soa']
@@ -818,7 +820,7 @@ class TestAXFR(TestXfrinConnection):
# This helper function creates a MockTSIGContext for a given key
# and TSIG error to be used as a result of verify (normally faked
# one)
- mock_ctx = MockTSIGContext(key)
+ mock_ctx = MockTSIGContext(key, TSIGContext.SIGN)
mock_ctx.error = error
if not has_last_signature:
mock_ctx.last_has_signature = lambda: False
@@ -1434,7 +1436,7 @@ class TestAXFR(TestXfrinConnection):
self.conn._tsig_key = TSIG_KEY
self.conn._tsig_ctx_creator = \
lambda key: self.__create_mock_tsig(key, None)
- self.conn._tsig_ctx = MockTSIGContext(TSIG_KEY)
+ self.conn._tsig_ctx = MockTSIGContext(TSIG_KEY, TSIGContext.VERIFY)
self.conn.response_generator = self._create_normal_response_data
self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
self.assertEqual(1, self.conn._tsig_ctx.verify_called)
@@ -1462,14 +1464,16 @@ class TestAXFR(TestXfrinConnection):
def test_do_xfrin_with_unexpected_tsig(self):
# XFR request wasn't signed, but response includes TSIG. Like BIND 9,
# we reject that.
- self.axfr_response_params['tsig_1st'] = TSIGContext(TSIG_KEY)
+ self.axfr_response_params['tsig_1st'] = \
+ TSIGContext(TSIG_KEY, TSIGContext.SIGN)
self.conn.response_generator = self._create_normal_response_data
self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
def test_do_xfrin_with_unexpected_tsig_for_second_message(self):
# similar to the previous test, but the first message is normal.
# the second one contains an unexpected TSIG. should be rejected.
- self.axfr_response_params['tsig_2nd'] = TSIGContext(TSIG_KEY)
+ self.axfr_response_params['tsig_2nd'] = \
+ TSIGContext(TSIG_KEY, TSIGContext.VERIFY)
self.conn.response_generator = self._create_normal_response_data
self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index 2b65311..40358c2 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -604,7 +604,8 @@ class XfrinConnection(asyncore.dispatcher):
self._tsig_ctx = None
# tsig_ctx_creator is introduced to allow tests to use a mock class for
# easier tests (in normal case we always use the default)
- self._tsig_ctx_creator = lambda key : TSIGContext(key)
+ self._tsig_ctx_creator = \
+ lambda key : TSIGContext(key, TSIGContext.SIGN)
# keep a record of this specific transfer to log on success
# (time, rr/s, etc)
diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
index 6e3f4a8..0903498 100644
--- a/src/bin/xfrout/tests/xfrout_test.py.in
+++ b/src/bin/xfrout/tests/xfrout_test.py.in
@@ -206,7 +206,7 @@ class TestXfroutSessionBase(unittest.TestCase):
# This helper function creates a MockTSIGContext for a given key
# and TSIG error to be used as a result of verify (normally faked
# one)
- mock_ctx = MockTSIGContext(TSIG_KEY)
+ mock_ctx = MockTSIGContext(TSIG_KEY, TSIGContext.SIGN)
mock_ctx.error = error
return mock_ctx
@@ -254,7 +254,7 @@ class TestXfroutSessionBase(unittest.TestCase):
renderer = MessageRenderer()
if with_tsig:
- tsig_ctx = MockTSIGContext(TSIG_KEY)
+ tsig_ctx = MockTSIGContext(TSIG_KEY, TSIGContext.SIGN)
msg.to_wire(renderer, tsig_ctx)
else:
msg.to_wire(renderer)
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index 835696e..781f3e0 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -178,8 +178,10 @@ class XfroutSession():
setattr(self, "_%s" % k, v)
self._handle()
- def create_tsig_ctx(self, tsig_record, tsig_key_ring):
- return TSIGContext(tsig_record.get_name(), tsig_record.get_rdata().get_algorithm(),
+ def create_tsig_ctx(self, tsig_record, operation, tsig_key_ring):
+ return TSIGContext(tsig_record.get_name(),
+ operation,
+ tsig_record.get_rdata().get_algorithm(),
tsig_key_ring)
def _handle(self):
@@ -224,6 +226,7 @@ class XfroutSession():
if tsig_record is not None:
self._tsig_len = tsig_record.get_length()
self._tsig_ctx = self.create_tsig_ctx(tsig_record,
+ TSIGContext.VERIFY,
self._tsig_key_ring)
tsig_error = self._tsig_ctx.verify(tsig_record, request_data)
if tsig_error != TSIGError.NOERROR:
diff --git a/src/lib/cryptolink/crypto_hmac.cc b/src/lib/cryptolink/crypto_hmac.cc
index c1bbfa8..5593caf 100644
--- a/src/lib/cryptolink/crypto_hmac.cc
+++ b/src/lib/cryptolink/crypto_hmac.cc
@@ -65,7 +65,10 @@ namespace cryptolink {
class HMACImpl {
public:
explicit HMACImpl(const void* secret, size_t secret_len,
- const HashAlgorithm hash_algorithm) {
+ const Operation operation,
+ const HashAlgorithm hash_algorithm) :
+ op_(operation)
+ {
Botan::HashFunction* hash;
try {
hash = Botan::get_hash(
@@ -130,6 +133,10 @@ public:
}
void update(const void* data, const size_t len) {
+ if ((op_ != Verify) && (op_ != Sign)) {
+ isc_throw(isc::cryptolink::IncompatibleOperation,
+ "Verify or Sign required");
+ }
try {
hmac_->update(static_cast<const Botan::byte*>(data), len);
} catch (const Botan::Exception& exc) {
@@ -138,6 +145,10 @@ public:
}
void sign(isc::util::OutputBuffer& result, size_t len) {
+ if (op_ != Sign) {
+ isc_throw(isc::cryptolink::IncompatibleOperation,
+ "Sign required");
+ }
try {
Botan::SecureVector<Botan::byte> b_result(hmac_->final());
@@ -151,6 +162,10 @@ public:
}
void sign(void* result, size_t len) {
+ if (op_ != Sign) {
+ isc_throw(isc::cryptolink::IncompatibleOperation,
+ "Sign required");
+ }
try {
Botan::SecureVector<Botan::byte> b_result(hmac_->final());
size_t output_size = getOutputLength();
@@ -164,6 +179,10 @@ public:
}
std::vector<uint8_t> sign(size_t len) {
+ if (op_ != Sign) {
+ isc_throw(isc::cryptolink::IncompatibleOperation,
+ "Sign required");
+ }
try {
Botan::SecureVector<Botan::byte> b_result(hmac_->final());
if (len == 0 || len > b_result.size()) {
@@ -178,6 +197,10 @@ public:
bool verify(const void* sig, size_t len) {
+ if (op_ != Verify) {
+ isc_throw(isc::cryptolink::IncompatibleOperation,
+ "Verify required");
+ }
// 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
@@ -205,12 +228,14 @@ public:
private:
boost::scoped_ptr<Botan::HMAC> hmac_;
+ const Operation op_;
};
HMAC::HMAC(const void* secret, size_t secret_length,
+ const Operation operation,
const HashAlgorithm hash_algorithm)
{
- impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
+ impl_ = new HMACImpl(secret, secret_length, operation, hash_algorithm);
}
HMAC::~HMAC() {
@@ -255,6 +280,7 @@ signHMAC(const void* data, const size_t data_len, const void* secret,
boost::scoped_ptr<HMAC> hmac(
CryptoLink::getCryptoLink().createHMAC(secret,
secret_len,
+ Sign,
hash_algorithm));
hmac->update(data, data_len);
hmac->sign(result, len);
@@ -269,6 +295,7 @@ verifyHMAC(const void* data, const size_t data_len, const void* secret,
boost::scoped_ptr<HMAC> hmac(
CryptoLink::getCryptoLink().createHMAC(secret,
secret_len,
+ Verify,
hash_algorithm));
hmac->update(data, data_len);
return (hmac->verify(sig, sig_len));
diff --git a/src/lib/cryptolink/crypto_hmac.h b/src/lib/cryptolink/crypto_hmac.h
index 2eb0d0e..dda1ae2 100644
--- a/src/lib/cryptolink/crypto_hmac.h
+++ b/src/lib/cryptolink/crypto_hmac.h
@@ -51,9 +51,11 @@ private:
/// \param len The length of the secret
/// \param hash_algorithm The hash algorithm
HMAC(const void* secret, size_t secret_len,
+ const Operation operation,
const HashAlgorithm hash_algorithm);
friend HMAC* CryptoLink::createHMAC(const void*, size_t,
+ const Operation,
const HashAlgorithm);
public:
diff --git a/src/lib/cryptolink/cryptolink.cc b/src/lib/cryptolink/cryptolink.cc
index d1c375d..23c3c6c 100644
--- a/src/lib/cryptolink/cryptolink.cc
+++ b/src/lib/cryptolink/cryptolink.cc
@@ -59,9 +59,10 @@ CryptoLink::initialize() {
HMAC*
CryptoLink::createHMAC(const void* secret, size_t secret_len,
+ const Operation operation,
const HashAlgorithm hash_algorithm)
{
- return (new HMAC(secret, secret_len, hash_algorithm));
+ return (new HMAC(secret, secret_len, operation, hash_algorithm));
}
} // namespace cryptolink
diff --git a/src/lib/cryptolink/cryptolink.h b/src/lib/cryptolink/cryptolink.h
index d0f7d38..4949e3f 100644
--- a/src/lib/cryptolink/cryptolink.h
+++ b/src/lib/cryptolink/cryptolink.h
@@ -27,6 +27,13 @@
namespace isc {
namespace cryptolink {
+/// \brief Crypto operations (Verify or Sign)
+enum Operation {
+ UNKNOWN_OP = 0, ///< To hide inheritance
+ Verify, ///< Verify
+ Sign ///< Sign
+};
+
/// \brief Hash algorithm identifiers
enum HashAlgorithm {
UNKNOWN_HASH = 0, ///< This value can be used in conversion
@@ -71,6 +78,14 @@ public:
CryptoLinkError(file, line, what) {}
};
+/// This exception is thrown when a cryptographic action is requested
+/// with an incompatible context.
+class IncompatibleOperation : public CryptoLinkError {
+public:
+ IncompatibleOperation(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 {
@@ -187,6 +202,7 @@ public:
/// \param secret_len The length of the secret
/// \param hash_algorithm The hash algorithm
HMAC* createHMAC(const void* secret, size_t secret_len,
+ const Operation operation,
const HashAlgorithm hash_algorithm);
private:
diff --git a/src/lib/cryptolink/tests/crypto_unittests.cc b/src/lib/cryptolink/tests/crypto_unittests.cc
index c8fe9c6..51fff45 100644
--- a/src/lib/cryptolink/tests/crypto_unittests.cc
+++ b/src/lib/cryptolink/tests/crypto_unittests.cc
@@ -100,6 +100,7 @@ namespace {
// Sign it
boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
secret_len,
+ Sign,
hash_algorithm),
deleteHMAC);
hmac_sign->update(data_buf.getData(), data_buf.getLength());
@@ -111,6 +112,7 @@ namespace {
// Check whether we can verify it ourselves
boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
secret_len,
+ Verify,
hash_algorithm),
deleteHMAC);
hmac_verify->update(data_buf.getData(), data_buf.getLength());
@@ -133,6 +135,7 @@ namespace {
CryptoLink& crypto = CryptoLink::getCryptoLink();
boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
secret_len,
+ Sign,
hash_algorithm),
deleteHMAC);
hmac_sign->update(data.c_str(), data.size());
@@ -142,6 +145,7 @@ namespace {
boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
secret_len,
+ Verify,
hash_algorithm),
deleteHMAC);
hmac_verify->update(data.c_str(), data.size());
@@ -160,6 +164,7 @@ namespace {
CryptoLink& crypto = CryptoLink::getCryptoLink();
boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
secret_len,
+ Sign,
hash_algorithm),
deleteHMAC);
hmac_sign->update(data.c_str(), data.size());
@@ -174,6 +179,7 @@ namespace {
boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
secret_len,
+ Verify,
hash_algorithm),
deleteHMAC);
hmac_verify->update(data.c_str(), data.size());
@@ -522,7 +528,7 @@ namespace {
size_t
sigVectorLength(HashAlgorithm alg, size_t len) {
boost::shared_ptr<HMAC> hmac_sign(
- CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
+ CryptoLink::getCryptoLink().createHMAC("asdf", 4, Sign, alg),
deleteHMAC);
hmac_sign->update("asdf", 4);
const std::vector<uint8_t> sig = hmac_sign->sign(len);
@@ -532,7 +538,7 @@ namespace {
size_t
sigBufferLength(HashAlgorithm alg, size_t len) {
boost::shared_ptr<HMAC> hmac_sign(
- CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
+ CryptoLink::getCryptoLink().createHMAC("asdf", 4, Sign, alg),
deleteHMAC);
hmac_sign->update("asdf", 4);
OutputBuffer sig(0);
@@ -586,8 +592,12 @@ TEST(CryptoLinkTest, BadKey) {
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(crypto.createHMAC(NULL, 0, Verify, MD5), BadKey);
+ EXPECT_THROW(crypto.createHMAC(NULL, 0, Sign, MD5), BadKey);
+ EXPECT_THROW(crypto.createHMAC(NULL, 0, Verify, UNKNOWN_HASH),
+ UnsupportedAlgorithm);
+ EXPECT_THROW(crypto.createHMAC(NULL, 0, Sign, UNKNOWN_HASH),
+ UnsupportedAlgorithm);
EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
NULL, 0, MD5, hmac_sig), BadKey);
@@ -604,8 +614,35 @@ TEST(CryptoLinkTest, BadKey) {
UnsupportedAlgorithm);
}
+TEST(CryptoLinkTest, IncompatibleOperation) {
+ const uint8_t secret[] = { 0x01, 0x02, 0x03, 0x04 };
+ OutputBuffer hmac_sig(20);
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+ boost::shared_ptr<HMAC> hmac(crypto.createHMAC(secret,
+ 4,
+ UNKNOWN_OP,
+ SHA1));
+ EXPECT_THROW(hmac->update(hmac_sig.getData(), 1), IncompatibleOperation);
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ 4,
+ Verify,
+ SHA1),
+ deleteHMAC);
+ EXPECT_THROW(hmac_sign->sign(hmac_sig, 20), IncompatibleOperation);
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ 4,
+ Sign,
+ SHA1),
+ deleteHMAC);
+ EXPECT_THROW(hmac_verify->verify(hmac_sig.getData(), 20),
+ IncompatibleOperation);
+}
+
TEST(CryptoLinkTest, Singleton) {
const CryptoLink& c1 = CryptoLink::getCryptoLink();
const CryptoLink& c2 = CryptoLink::getCryptoLink();
ASSERT_EQ(&c1, &c2);
}
+
+
diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc
index 23ed463..a7a2967 100644
--- a/src/lib/dns/python/pydnspp.cc
+++ b/src/lib/dns/python/pydnspp.cc
@@ -690,6 +690,11 @@ initModulePart_TSIGContext(PyObject* mod) {
installClassVariable(tsigcontext_type, "DEFAULT_FUDGE",
Py_BuildValue("H", TSIGContext::DEFAULT_FUDGE));
+
+ installClassVariable(tsigcontext_type, "VERIFY",
+ Py_BuildValue("I", isc::cryptolink::Verify));
+ installClassVariable(tsigcontext_type, "SIGN",
+ Py_BuildValue("I", isc::cryptolink::Sign));
} catch (const std::exception& ex) {
const std::string ex_what =
"Unexpected failure in TSIGContext initialization: " +
diff --git a/src/lib/dns/python/tests/message_python_test.py b/src/lib/dns/python/tests/message_python_test.py
index b9c0d5c..d808483 100644
--- a/src/lib/dns/python/tests/message_python_test.py
+++ b/src/lib/dns/python/tests/message_python_test.py
@@ -95,7 +95,7 @@ class MessageTest(unittest.TestCase):
self.bogus_section = Message.SECTION_ADDITIONAL + 1
self.bogus_below_section = Message.SECTION_QUESTION - 1
self.tsig_key = TSIGKey("www.example.com:SFuWd/q99SzF8Yzd1QbB9g==")
- self.tsig_ctx = TSIGContext(self.tsig_key)
+ self.tsig_ctx = TSIGContext(self.tsig_key, TSIGContext.SIGN)
def tearDown(self):
# reset any faked current time setting (it would affect other tests)
@@ -360,16 +360,16 @@ class MessageTest(unittest.TestCase):
self.r.add_question(Question(Name("www.example.com"),
RRClass("IN"), rrtype))
- def __common_tsig_checks(self, expected_file):
+ def __common_tsig_checks(self, expected_file, tsigctx):
renderer = MessageRenderer()
- self.r.to_wire(renderer, self.tsig_ctx)
+ self.r.to_wire(renderer, tsigctx)
self.assertEqual(read_wire_data(expected_file), renderer.get_data())
def test_to_wire_with_tsig(self):
fix_current_time(0x4da8877a)
self.r.set_qid(0x2d65)
self.__common_tsigmessage_setup()
- self.__common_tsig_checks("message_toWire2.wire")
+ self.__common_tsig_checks("message_toWire2.wire", self.tsig_ctx)
def test_to_wire_with_edns_tsig(self):
fix_current_time(0x4db60d1f)
@@ -378,33 +378,35 @@ class MessageTest(unittest.TestCase):
edns = EDNS()
edns.set_udp_size(4096)
self.r.set_edns(edns)
- self.__common_tsig_checks("message_toWire3.wire")
+ self.__common_tsig_checks("message_toWire3.wire", self.tsig_ctx)
def test_to_wire_tsig_truncation(self):
fix_current_time(0x4e179212)
data = factoryFromFile(self.p, "message_fromWire17.wire")
+ tsig_ctx_copy = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
self.assertEqual(TSIGError.NOERROR,
- self.tsig_ctx.verify(self.p.get_tsig_record(), data))
+ tsig_ctx_copy.verify(self.p.get_tsig_record(), data))
self.r.set_qid(0x22c2)
self.__common_tsigmessage_setup([Message.HEADERFLAG_QR,
Message.HEADERFLAG_AA,
Message.HEADERFLAG_RD],
RRType("TXT"),
[LONG_TXT1, LONG_TXT2])
- self.__common_tsig_checks("message_toWire4.wire")
+ self.__common_tsig_checks("message_toWire4.wire", tsig_ctx_copy)
def test_to_wire_tsig_truncation2(self):
fix_current_time(0x4e179212)
data = factoryFromFile(self.p, "message_fromWire17.wire")
+ tsig_ctx_copy = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
self.assertEqual(TSIGError.NOERROR,
- self.tsig_ctx.verify(self.p.get_tsig_record(), data))
+ tsig_ctx_copy.verify(self.p.get_tsig_record(), data))
self.r.set_qid(0x22c2)
self.__common_tsigmessage_setup([Message.HEADERFLAG_QR,
Message.HEADERFLAG_AA,
Message.HEADERFLAG_RD],
RRType("TXT"),
[LONG_TXT1, LONG_TXT3])
- self.__common_tsig_checks("message_toWire4.wire")
+ self.__common_tsig_checks("message_toWire4.wire", tsig_ctx_copy)
def test_to_wire_tsig_truncation3(self):
self.r.set_opcode(Opcode.QUERY())
@@ -423,15 +425,16 @@ class MessageTest(unittest.TestCase):
def test_to_wire_tsig_no_truncation(self):
fix_current_time(0x4e17b38d)
data = factoryFromFile(self.p, "message_fromWire18.wire")
+ tsig_ctx_copy = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
self.assertEqual(TSIGError.NOERROR,
- self.tsig_ctx.verify(self.p.get_tsig_record(), data))
+ tsig_ctx_copy.verify(self.p.get_tsig_record(), data))
self.r.set_qid(0xd6e2)
self.__common_tsigmessage_setup([Message.HEADERFLAG_QR,
Message.HEADERFLAG_AA,
Message.HEADERFLAG_RD],
RRType("TXT"),
[LONG_TXT1, LONG_TXT4])
- self.__common_tsig_checks("message_toWire5.wire")
+ self.__common_tsig_checks("message_toWire5.wire", tsig_ctx_copy)
def test_to_wire_tsig_length_errors(self):
renderer = MessageRenderer()
diff --git a/src/lib/dns/python/tests/tsig_python_test.py b/src/lib/dns/python/tests/tsig_python_test.py
index 4d99175..1cddcb0 100644
--- a/src/lib/dns/python/tests/tsig_python_test.py
+++ b/src/lib/dns/python/tests/tsig_python_test.py
@@ -35,8 +35,8 @@ class TSIGContextTest(unittest.TestCase):
fix_current_time(None)
self.qid = 0x2d65
self.test_name = Name("www.example.com")
- self.tsig_ctx = TSIGContext(self.tsig_key)
- self.tsig_verify_ctx = TSIGContext(self.tsig_key)
+ self.tsig_ctx = TSIGContext(self.tsig_key, TSIGContext.SIGN)
+ self.tsig_verify_ctx = TSIGContext(self.tsig_key, TSIGContext.VERIFY)
self.keyring = TSIGKeyRing()
self.message = Message(Message.RENDER)
self.renderer = MessageRenderer()
@@ -45,7 +45,8 @@ class TSIGContextTest(unittest.TestCase):
self.secret = base64.b64decode(b"SFuWd/q99SzF8Yzd1QbB9g==")
self.tsig_ctx = TSIGContext(TSIGKey(self.test_name,
TSIGKey.HMACMD5_NAME,
- self.secret))
+ self.secret),
+ TSIGContext.SIGN)
self.badkey_name = Name("badkey.example.com")
self.dummy_record = TSIGRecord(self.badkey_name,
TSIG("hmac-md5.sig-alg.reg.int. " + \
@@ -142,7 +143,8 @@ class TSIGContextTest(unittest.TestCase):
def test_from_keyring(self):
# Construct a TSIG context with an empty key ring. Key shouldn't be
# found, and the BAD_KEY error should be recorded.
- ctx = TSIGContext(self.test_name, TSIGKey.HMACMD5_NAME, self.keyring)
+ ctx = TSIGContext(self.test_name, TSIGContext.SIGN,
+ TSIGKey.HMACMD5_NAME, self.keyring)
self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
# check get_error() doesn't cause ref leak. Note: we can't
@@ -154,24 +156,26 @@ class TSIGContextTest(unittest.TestCase):
# construct it again. This time it should be constructed with a valid
# key.
self.keyring.add(TSIGKey(self.test_name, TSIGKey.HMACMD5_NAME, b""))
- ctx = TSIGContext(self.test_name, TSIGKey.HMACMD5_NAME, self.keyring)
+ ctx = TSIGContext(self.test_name, TSIGContext.SIGN,
+ TSIGKey.HMACMD5_NAME, self.keyring)
self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
self.assertEqual(TSIGError.NOERROR, ctx.get_error())
# Similar to the first case except that the key ring isn't empty but
# it doesn't contain a matching key.
- ctx = TSIGContext(self.test_name, TSIGKey.HMACSHA1_NAME, self.keyring)
+ ctx = TSIGContext(self.test_name, TSIGContext.SIGN,
+ TSIGKey.HMACSHA1_NAME, self.keyring)
self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
- ctx = TSIGContext(Name("different-key.example"),
+ ctx = TSIGContext(Name("different-key.example"), TSIGContext.SIGN,
TSIGKey.HMACMD5_NAME, self.keyring)
self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
# "Unknown" algorithm name will result in BADKEY, too.
- ctx = TSIGContext(self.test_name, Name("unknown.algorithm"),
- self.keyring)
+ ctx = TSIGContext(self.test_name, TSIGContext.SIGN,
+ Name("unknown.algorithm"), self.keyring)
self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
@@ -188,7 +192,8 @@ class TSIGContextTest(unittest.TestCase):
def test_sign_using_uppercase_keyname(self):
fix_current_time(0x4da8877a)
cap_ctx = TSIGContext(TSIGKey(Name("WWW.EXAMPLE.COM"),
- TSIGKey.HMACMD5_NAME, self.secret))
+ TSIGKey.HMACMD5_NAME, self.secret),
+ TSIGContext.SIGN)
tsig = self.createMessageAndSign(self.qid, self.test_name, cap_ctx)
self.commonSignChecks(tsig, self.qid, 0x4da8877a, COMMON_EXPECTED_MAC)
@@ -197,7 +202,8 @@ class TSIGContextTest(unittest.TestCase):
fix_current_time(0x4da8877a)
cap_ctx = TSIGContext(TSIGKey(self.test_name,
Name("HMAC-md5.SIG-alg.REG.int"),
- self.secret))
+ self.secret),
+ TSIGContext.SIGN)
tsig = self.createMessageAndSign(self.qid, self.test_name, cap_ctx)
self.commonSignChecks(tsig, self.qid, 0x4da8877a, COMMON_EXPECTED_MAC)
@@ -221,15 +227,17 @@ class TSIGContextTest(unittest.TestCase):
# the data must at least hold the DNS message header and the specified
# TSIG.
bad_len = 12 + self.dummy_record.get_length() - 1
- self.assertRaises(InvalidParameter, self.tsig_ctx.verify,
+ self.assertRaises(InvalidParameter, self.tsig_verify_ctx.verify,
self.dummy_record, DUMMY_DATA[:bad_len])
def test_sign_using_hmacsha1(self):
fix_current_time(0x4dae7d5f)
secret = base64.b64decode(b"MA+QDhXbyqUak+qnMFyTyEirzng=")
- sha1_ctx = TSIGContext(TSIGKey(self.test_name, TSIGKey.HMACSHA1_NAME,
- secret))
+ sha1_ctx = TSIGContext(TSIGKey(self.test_name,
+ TSIGKey.HMACSHA1_NAME,
+ secret),
+ TSIGContext.SIGN)
qid = 0x0967
expected_mac = b"\x41\x53\x40\xc7\xda\xf8\x24\xed\x68\x4e\xe5\x86" + \
b"\xf7\xb5\xa6\x7a\x2f\xeb\xc0\xd3"
@@ -246,8 +254,9 @@ class TSIGContextTest(unittest.TestCase):
self.received_data, TSIGError.NOERROR,
TSIGContext.STATE_RECEIVED_REQUEST)
+ tsig_ctx_copy = TSIGContext(self.tsig_verify_ctx, TSIGContext.SIGN)
tsig = self.createMessageAndSign(self.qid, self.test_name,
- self.tsig_verify_ctx,
+ tsig_ctx_copy,
QR_FLAG|AA_FLAG|RD_FLAG,
RRType.A(), "192.0.2.1")
@@ -287,28 +296,30 @@ class TSIGContextTest(unittest.TestCase):
TSIGError.NOERROR,
TSIGContext.STATE_RECEIVED_REQUEST)
+ tsig_ctx_copy = TSIGContext(self.tsig_verify_ctx, TSIGContext.SIGN)
tsig = self.createMessageAndSign(axfr_qid, zone_name,
- self.tsig_verify_ctx,
+ tsig_ctx_copy,
AA_FLAG|QR_FLAG, RRType.AXFR(),
"ns.example.com. root.example.com." +\
" 2011041503 7200 3600 2592000 1200",
RRType.SOA())
received_data = read_wire_data("tsig_verify2.wire")
- self.commonVerifyChecks(self.tsig_ctx, tsig, received_data,
+ tsig_ctx_copy2 = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
+ self.commonVerifyChecks(tsig_ctx_copy2, tsig, received_data,
TSIGError.NOERROR)
expected_mac = b"\x10\x24\x58\xf7\xf6\x2d\xdd\x7d\x63\x8d\x74" +\
b"\x60\x34\x13\x09\x68"
tsig = self.createMessageAndSign(axfr_qid, zone_name,
- self.tsig_verify_ctx,
+ tsig_ctx_copy,
AA_FLAG|QR_FLAG, RRType.AXFR(),
"ns.example.com.", RRType.NS(),
False)
self.commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac)
received_data = read_wire_data("tsig_verify3.wire")
- self.commonVerifyChecks(self.tsig_ctx, tsig, received_data,
+ self.commonVerifyChecks(tsig_ctx_copy2, tsig, received_data,
TSIGError.NOERROR)
def test_badtime_response(self):
@@ -326,8 +337,9 @@ class TSIGContextTest(unittest.TestCase):
TSIGContext.STATE_RECEIVED_REQUEST)
# make and sign a response in the context of TSIG error.
+ tsig_ctx_copy = TSIGContext(self.tsig_verify_ctx, TSIGContext.SIGN)
tsig = self.createMessageAndSign(test_qid, self.test_name,
- self.tsig_verify_ctx,
+ tsig_ctx_copy,
QR_FLAG, RRType.SOA(), None, None,
True, Rcode.NOTAUTH())
@@ -397,35 +409,42 @@ class TSIGContextTest(unittest.TestCase):
# Try to sign a simple message with bogus secret. It should fail
# with BADSIG.
self.createMessageFromFile("message_toWire2.wire")
- bad_ctx = TSIGContext(TSIGKey(self.test_name, TSIGKey.HMACMD5_NAME,
- DUMMY_DATA))
- self.commonVerifyChecks(bad_ctx, self.message.get_tsig_record(),
+ bad_vrfy_ctx = TSIGContext(TSIGKey(self.test_name,
+ TSIGKey.HMACMD5_NAME,
+ DUMMY_DATA),
+ TSIGContext.VERIFY)
+ self.commonVerifyChecks(bad_vrfy_ctx, self.message.get_tsig_record(),
self.received_data, TSIGError.BAD_SIG,
TSIGContext.STATE_RECEIVED_REQUEST)
# Sign the same message (which doesn't matter for this test) with the
# context of "checked state".
- tsig = self.createMessageAndSign(self.qid, self.test_name, bad_ctx)
+ bad_sign_ctx = TSIGContext(bad_vrfy_ctx, TSIGContext.SIGN)
+ tsig = self.createMessageAndSign(self.qid, self.test_name,
+ bad_sign_ctx)
self.commonSignChecks(tsig, self.message.get_qid(), 0x4da8877a, None,
16) # 16: BADSIG
def test_badkey_response(self):
# A similar test as badsigResponse but for BADKEY
fix_current_time(0x4da8877a)
- tsig_ctx = TSIGContext(self.badkey_name, TSIGKey.HMACMD5_NAME,
- self.keyring)
- self.commonVerifyChecks(tsig_ctx, self.dummy_record, DUMMY_DATA,
- TSIGError.BAD_KEY,
+ tsig_vrfy_ctx = TSIGContext(self.badkey_name, TSIGContext.VERIFY,
+ TSIGKey.HMACMD5_NAME, self.keyring)
+ self.commonVerifyChecks(tsig_vrfy_ctx, self.dummy_record,
+ DUMMY_DATA, TSIGError.BAD_KEY,
TSIGContext.STATE_RECEIVED_REQUEST)
- sig = self.createMessageAndSign(self.qid, self.test_name, tsig_ctx)
+ tsig_sign_ctx = TSIGContext(tsig_vrfy_ctx, TSIGContext.SIGN)
+ sig = self.createMessageAndSign(self.qid, self.test_name,
+ tsig_sign_ctx)
self.assertEqual(self.badkey_name, sig.get_name())
self.commonSignChecks(sig, self.qid, 0x4da8877a, None, 17) # 17: BADKEY
def test_badkey_for_response(self):
# "BADKEY" case for a response to a signed message
self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
- self.commonVerifyChecks(self.tsig_ctx, self.dummy_record, DUMMY_DATA,
+ tsig_ctx_copy = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
+ self.commonVerifyChecks(tsig_ctx_copy, self.dummy_record, DUMMY_DATA,
TSIGError.BAD_KEY,
TSIGContext.STATE_SENT_REQUEST)
@@ -433,7 +452,7 @@ class TSIGContextTest(unittest.TestCase):
dummy_record = TSIGRecord(self.test_name,
TSIG("hmac-sha1. 1302890362 300 0 "
"11621 0 0"))
- self.commonVerifyChecks(self.tsig_ctx, dummy_record, DUMMY_DATA,
+ self.commonVerifyChecks(tsig_ctx_copy, dummy_record, DUMMY_DATA,
TSIGError.BAD_KEY,
TSIGContext.STATE_SENT_REQUEST)
@@ -446,12 +465,13 @@ class TSIGContextTest(unittest.TestCase):
self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
self.createMessageFromFile("tsig_verify4.wire")
- self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
+ tsig_ctx_copy = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
+ self.commonVerifyChecks(tsig_ctx_copy, self.message.get_tsig_record(),
self.received_data, TSIGError.BAD_SIG,
TSIGContext.STATE_SENT_REQUEST)
self.createMessageFromFile("tsig_verify5.wire")
- self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
+ self.commonVerifyChecks(tsig_ctx_copy, self.message.get_tsig_record(),
self.received_data, TSIGError.NOERROR,
TSIGContext.STATE_VERIFIED_RESPONSE)
@@ -461,12 +481,13 @@ class TSIGContextTest(unittest.TestCase):
fix_current_time(0x4da8877a)
self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
- self.commonVerifyChecks(self.tsig_ctx, None, DUMMY_DATA,
+ tsig_ctx_copy = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
+ self.commonVerifyChecks(tsig_ctx_copy, None, DUMMY_DATA,
TSIGError.FORMERR, TSIGContext.STATE_SENT_REQUEST,
True)
self.createMessageFromFile("tsig_verify5.wire")
- self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
+ self.commonVerifyChecks(tsig_ctx_copy, self.message.get_tsig_record(),
self.received_data, TSIGError.NOERROR,
TSIGContext.STATE_VERIFIED_RESPONSE)
@@ -479,13 +500,14 @@ class TSIGContextTest(unittest.TestCase):
# "advance the clock" and try validating, which should fail due to
# BADTIME
fix_current_time(0x4da8877a + 600)
- self.commonVerifyChecks(self.tsig_ctx, tsig, DUMMY_DATA,
+ tsig_ctx_copy = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
+ self.commonVerifyChecks(tsig_ctx_copy, tsig, DUMMY_DATA,
TSIGError.BAD_TIME, TSIGContext.STATE_SENT_REQUEST)
# revert the clock again.
fix_current_time(0x4da8877a)
self.createMessageFromFile("tsig_verify5.wire")
- self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
+ self.commonVerifyChecks(tsig_ctx_copy, self.message.get_tsig_record(),
self.received_data, TSIGError.NOERROR,
TSIGContext.STATE_VERIFIED_RESPONSE)
@@ -520,16 +542,18 @@ class TSIGContextTest(unittest.TestCase):
self.received_data)
self.assertEqual(TSIGContext.STATE_RECEIVED_REQUEST,
self.tsig_verify_ctx.get_state())
+ tsig_ctx_copy = TSIGContext(self.tsig_verify_ctx, TSIGContext.SIGN)
self.createMessageAndSign(self.qid, self.test_name,
- self.tsig_verify_ctx,
+ tsig_ctx_copy,
QR_FLAG|AA_FLAG|RD_FLAG, RRType.A(),
"192.0.2.1")
self.assertEqual(TSIGContext.STATE_SENT_RESPONSE,
- self.tsig_verify_ctx.get_state())
+ tsig_ctx_copy.get_state())
# Now trying further verification.
self.createMessageFromFile("message_toWire2.wire")
- self.assertRaises(TSIGContextError, self.tsig_verify_ctx.verify,
+ tsig_ctx_copy2 = TSIGContext(tsig_ctx_copy, TSIGContext.VERIFY)
+ self.assertRaises(TSIGContextError, tsig_ctx_copy2.verify,
self.message.get_tsig_record(), self.received_data)
# Likewise, once the context verifies a response, it shouldn't for
@@ -539,14 +563,16 @@ class TSIGContextTest(unittest.TestCase):
self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
self.createMessageFromFile("tsig_verify5.wire")
- self.tsig_ctx.verify(self.message.get_tsig_record(),
+ tsig_ctx_copy = TSIGContext(self.tsig_ctx, TSIGContext.VERIFY)
+ tsig_ctx_copy.verify(self.message.get_tsig_record(),
self.received_data)
self.assertEqual(TSIGContext.STATE_VERIFIED_RESPONSE,
- self.tsig_ctx.get_state())
+ tsig_ctx_copy.get_state())
# Now trying further signing.
+ tsig_ctx_copy2 = TSIGContext(tsig_ctx_copy, TSIGContext.SIGN)
self.assertRaises(TSIGContextError, self.createMessageAndSign,
- self.qid, self.test_name, self.tsig_ctx)
+ self.qid, self.test_name, tsig_ctx_copy2)
# Too short MAC should be rejected.
# Note: when we implement RFC4635-based checks, the error code will
diff --git a/src/lib/dns/python/tsig_python.cc b/src/lib/dns/python/tsig_python.cc
index abb7733..6f74b1b 100644
--- a/src/lib/dns/python/tsig_python.cc
+++ b/src/lib/dns/python/tsig_python.cc
@@ -101,8 +101,30 @@ TSIGContext_init(s_TSIGContext* self, PyObject* args) {
try {
// "From key" constructor
const PyObject* tsigkey_obj;
- if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey_obj)) {
- self->cppobj = new TSIGContext(PyTSIGKey_ToTSIGKey(tsigkey_obj));
+ int op;
+
+ if (PyArg_ParseTuple(args, "O!i", &tsigkey_type, &tsigkey_obj, &op)) {
+ if ((op != isc::cryptolink::Verify) &&
+ (op != isc::cryptolink::Sign)) {
+ goto badop;
+ }
+ self->cppobj =
+ new TSIGContext(PyTSIGKey_ToTSIGKey(tsigkey_obj),
+ static_cast<isc::cryptolink::Operation>(op));
+ return (0);
+ }
+
+ // "From context" copy constructor
+ PyObject* tsigcontext_obj;
+ if (PyArg_ParseTuple(args, "O!i", &tsigcontext_type,
+ &tsigcontext_obj, &op)) {
+ if ((op != isc::cryptolink::Verify) &&
+ (op != isc::cryptolink::Sign)) {
+ goto badop;
+ }
+ self->cppobj =
+ new TSIGContext(PyTSIGContext_ToTSIGContext(tsigcontext_obj),
+ static_cast<isc::cryptolink::Operation>(op));
return (0);
}
@@ -111,10 +133,15 @@ TSIGContext_init(s_TSIGContext* self, PyObject* args) {
const PyObject* keyname_obj;
const PyObject* algname_obj;
const PyObject* keyring_obj;
- if (PyArg_ParseTuple(args, "O!O!O!", &name_type, &keyname_obj,
+ if (PyArg_ParseTuple(args, "O!iO!O!", &name_type, &keyname_obj, &op,
&name_type, &algname_obj, &tsigkeyring_type,
&keyring_obj)) {
+ if ((op != isc::cryptolink::Verify) &&
+ (op != isc::cryptolink::Sign)) {
+ goto badop;
+ }
self->cppobj = new TSIGContext(PyName_ToName(keyname_obj),
+ static_cast<isc::cryptolink::Operation>(op),
PyName_ToName(algname_obj),
PyTSIGKeyRing_ToTSIGKeyRing(keyring_obj));
return (0);
@@ -134,6 +161,11 @@ TSIGContext_init(s_TSIGContext* self, PyObject* args) {
"Invalid arguments to TSIGContext constructor");
return (-1);
+
+badop:
+ PyErr_SetString(po_IscException,
+ "VERIFY or SIGN required in constructing TSIGContext");
+ return (-1);
}
void
diff --git a/src/lib/dns/tests/message_unittest.cc b/src/lib/dns/tests/message_unittest.cc
index 835aa48..bbedc55 100644
--- a/src/lib/dns/tests/message_unittest.cc
+++ b/src/lib/dns/tests/message_unittest.cc
@@ -84,7 +84,11 @@ protected:
bogus_section(static_cast<Message::Section>(
Message::SECTION_ADDITIONAL + 1)),
tsig_ctx(TSIGKey("www.example.com:"
- "SFuWd/q99SzF8Yzd1QbB9g=="))
+ "SFuWd/q99SzF8Yzd1QbB9g=="),
+ isc::cryptolink::Sign),
+ tsig_verify_ctx(TSIGKey("www.example.com:"
+ "SFuWd/q99SzF8Yzd1QbB9g=="),
+ isc::cryptolink::Verify)
{
rrset_a = RRsetPtr(new RRset(test_name, RRClass::IN(),
RRType::A(), RRTTL(3600)));
@@ -114,6 +118,7 @@ protected:
RRsetPtr rrset_aaaa; // AAAA RRset with one RDATA with RRSIG
RRsetPtr rrset_rrsig; // RRSIG for the AAAA RRset
TSIGContext tsig_ctx;
+ TSIGContext tsig_verify_ctx;
vector<unsigned char> received_data;
vector<unsigned char> expected_data;
@@ -940,16 +945,17 @@ TEST_F(MessageTest, toWireTSIGTruncation) {
factoryFromFile(message_parse, "message_fromWire17.wire");
EXPECT_EQ(TSIGError::NOERROR(),
- tsig_ctx.verify(message_parse.getTSIGRecord(),
- &received_data[0], received_data.size()));
+ tsig_verify_ctx.verify(message_parse.getTSIGRecord(),
+ &received_data[0], received_data.size()));
message_render.setQid(0x22c2);
vector<const char*> answer_data;
answer_data.push_back(long_txt1);
answer_data.push_back(long_txt2);
+ TSIGContext tsig_ctx_copy(tsig_verify_ctx, isc::cryptolink::Sign);
{
SCOPED_TRACE("Message sign with TSIG and TC bit on");
- commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx_copy,
"message_toWire4.wire",
QR_FLAG|AA_FLAG|RD_FLAG,
RRType::TXT(), &answer_data);
@@ -962,16 +968,17 @@ TEST_F(MessageTest, toWireTSIGTruncation2) {
isc::util::detail::gettimeFunction = testGetTime<0x4e179212>;
factoryFromFile(message_parse, "message_fromWire17.wire");
EXPECT_EQ(TSIGError::NOERROR(),
- tsig_ctx.verify(message_parse.getTSIGRecord(),
- &received_data[0], received_data.size()));
+ tsig_verify_ctx.verify(message_parse.getTSIGRecord(),
+ &received_data[0], received_data.size()));
message_render.setQid(0x22c2);
vector<const char*> answer_data;
answer_data.push_back(long_txt1);
answer_data.push_back(long_txt3);
+ TSIGContext tsig_ctx_copy(tsig_verify_ctx, isc::cryptolink::Sign);
{
SCOPED_TRACE("Message sign with TSIG and TC bit on (2)");
- commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx_copy,
"message_toWire4.wire",
QR_FLAG|AA_FLAG|RD_FLAG,
RRType::TXT(), &answer_data);
@@ -1017,16 +1024,17 @@ TEST_F(MessageTest, toWireTSIGNoTruncation) {
isc::util::detail::gettimeFunction = testGetTime<0x4e17b38d>;
factoryFromFile(message_parse, "message_fromWire18.wire");
EXPECT_EQ(TSIGError::NOERROR(),
- tsig_ctx.verify(message_parse.getTSIGRecord(),
- &received_data[0], received_data.size()));
+ tsig_verify_ctx.verify(message_parse.getTSIGRecord(),
+ &received_data[0], received_data.size()));
message_render.setQid(0xd6e2);
vector<const char*> answer_data;
answer_data.push_back(long_txt1);
answer_data.push_back(long_txt4);
+ TSIGContext tsig_ctx_copy(tsig_verify_ctx, isc::cryptolink::Sign);
{
SCOPED_TRACE("Message sign with TSIG, no truncation");
- commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx_copy,
"message_toWire5.wire",
QR_FLAG|AA_FLAG|RD_FLAG,
RRType::TXT(), &answer_data);
diff --git a/src/lib/dns/tests/tsig_unittest.cc b/src/lib/dns/tests/tsig_unittest.cc
index 458a6e0..68f357b 100644
--- a/src/lib/dns/tests/tsig_unittest.cc
+++ b/src/lib/dns/tests/tsig_unittest.cc
@@ -47,6 +47,7 @@ using namespace isc::dns;
using namespace isc::util;
using namespace isc::util::encode;
using namespace isc::dns::rdata;
+using namespace isc::cryptolink;
using isc::UnitTestUtil;
// See dnssectime.cc
@@ -70,12 +71,18 @@ testGetTime() {
// update method.
class TestTSIGContext : public TSIGContext {
public:
- TestTSIGContext(const TSIGKey& key) :
- TSIGContext(key)
+ TestTSIGContext(const TSIGKey& key, const Operation operation) :
+ TSIGContext(key, operation)
{}
- TestTSIGContext(const Name& key_name, const Name& algorithm_name,
+ TestTSIGContext(const TSIGContext& other,
+ const Operation operation) :
+ TSIGContext(other, operation)
+ {}
+ TestTSIGContext(const Name& key_name,
+ const Operation operation,
+ const Name& algorithm_name,
const TSIGKeyRing& keyring) :
- TSIGContext(key_name, algorithm_name, keyring)
+ TSIGContext(key_name, operation, algorithm_name, keyring)
{}
void update(const void* const data, size_t len) {
TSIGContext::update(data, len);
@@ -85,7 +92,8 @@ public:
class TSIGTest : public ::testing::Test {
protected:
TSIGTest() :
- tsig_ctx(NULL), qid(0x2d65), test_name("www.example.com"),
+ tsig_ctx(NULL), tsig_verify_ctx(NULL),
+ qid(0x2d65), test_name("www.example.com"),
badkey_name("badkey.example.com"), test_class(RRClass::IN()),
test_ttl(86400), message(Message::RENDER),
dummy_data(1024, 0xdd), // should be sufficiently large for all tests
@@ -102,11 +110,13 @@ protected:
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACMD5_NAME(),
&secret[0],
- secret.size())));
+ secret.size()),
+ Sign));
tsig_verify_ctx.reset(new TSIGContext(TSIGKey(test_name,
TSIGKey::HMACMD5_NAME(),
&secret[0],
- secret.size())));
+ secret.size()),
+ Verify));
}
~TSIGTest() {
isc::util::detail::gettimeFunction = NULL;
@@ -266,7 +276,7 @@ TEST_F(TSIGTest, initialState) {
TEST_F(TSIGTest, constructFromKeyRing) {
// Construct a TSIG context with an empty key ring. Key shouldn't be
// found, and the BAD_KEY error should be recorded.
- TSIGContext ctx1(test_name, TSIGKey::HMACMD5_NAME(), keyring);
+ TSIGContext ctx1(test_name, UNKNOWN_OP, TSIGKey::HMACMD5_NAME(), keyring);
EXPECT_EQ(TSIGContext::INIT, ctx1.getState());
EXPECT_EQ(TSIGError::BAD_KEY(), ctx1.getError());
@@ -274,23 +284,26 @@ TEST_F(TSIGTest, constructFromKeyRing) {
// construct it again. This time it should be constructed with a valid
// key.
keyring.add(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(), NULL, 0));
- TSIGContext ctx2(test_name, TSIGKey::HMACMD5_NAME(), keyring);
+ TSIGContext ctx2(test_name, UNKNOWN_OP, TSIGKey::HMACMD5_NAME(), keyring);
EXPECT_EQ(TSIGContext::INIT, ctx2.getState());
EXPECT_EQ(TSIGError::NOERROR(), ctx2.getError());
// Similar to the first case except that the key ring isn't empty but
// it doesn't contain a matching key.
- TSIGContext ctx3(test_name, TSIGKey::HMACSHA1_NAME(), keyring);
+ TSIGContext ctx3(test_name, UNKNOWN_OP, TSIGKey::HMACSHA1_NAME(), keyring);
EXPECT_EQ(TSIGContext::INIT, ctx3.getState());
EXPECT_EQ(TSIGError::BAD_KEY(), ctx3.getError());
- TSIGContext ctx4(Name("different-key.example"), TSIGKey::HMACMD5_NAME(),
+ TSIGContext ctx4(Name("different-key.example"),
+ UNKNOWN_OP,
+ TSIGKey::HMACMD5_NAME(),
keyring);
EXPECT_EQ(TSIGContext::INIT, ctx4.getState());
EXPECT_EQ(TSIGError::BAD_KEY(), ctx4.getError());
// "Unknown" algorithm name will result in BADKEY, too.
- TSIGContext ctx5(test_name, Name("unknown.algorithm"), keyring);
+ TSIGContext ctx5(test_name, UNKNOWN_OP,
+ Name("unknown.algorithm"), keyring);
EXPECT_EQ(TSIGContext::INIT, ctx5.getState());
EXPECT_EQ(TSIGError::BAD_KEY(), ctx5.getError());
}
@@ -323,7 +336,8 @@ TEST_F(TSIGTest, signUsingUpperCasedKeyName) {
TSIGContext cap_ctx(TSIGKey(Name("WWW.EXAMPLE.COM"),
TSIGKey::HMACMD5_NAME(),
- &secret[0], secret.size()));
+ &secret[0], secret.size()),
+ Sign);
{
SCOPED_TRACE("Sign test for query using non canonical key name");
@@ -339,7 +353,8 @@ TEST_F(TSIGTest, signUsingUpperCasedAlgorithmName) {
TSIGContext cap_ctx(TSIGKey(test_name,
Name("HMAC-md5.SIG-alg.REG.int"),
- &secret[0], secret.size()));
+ &secret[0], secret.size()),
+ Sign);
{
SCOPED_TRACE("Sign test for query using non canonical algorithm name");
@@ -380,20 +395,20 @@ TEST_F(TSIGTest, signBadData) {
TEST_F(TSIGTest, verifyBadData) {
// the data must at least hold the DNS message header and the specified
// TSIG.
- EXPECT_THROW(tsig_ctx->verify(&dummy_record, &dummy_data[0],
- 12 + dummy_record.getLength() - 1),
+ EXPECT_THROW(tsig_verify_ctx->verify(&dummy_record, &dummy_data[0],
+ 12 + dummy_record.getLength() - 1),
InvalidParameter);
// Still nothing verified
- EXPECT_THROW(tsig_ctx->lastHadSignature(), TSIGContextError);
+ EXPECT_THROW(tsig_verify_ctx->lastHadSignature(), TSIGContextError);
// And the data must not be NULL.
- EXPECT_THROW(tsig_ctx->verify(&dummy_record, NULL,
- 12 + dummy_record.getLength()),
+ EXPECT_THROW(tsig_verify_ctx->verify(&dummy_record, NULL,
+ 12 + dummy_record.getLength()),
InvalidParameter);
// Still nothing verified
- EXPECT_THROW(tsig_ctx->lastHadSignature(), TSIGContextError);
+ EXPECT_THROW(tsig_verify_ctx->lastHadSignature(), TSIGContextError);
}
@@ -412,19 +427,20 @@ TEST_F(TSIGTest, signExceptionSafety) {
commonVerifyChecks(*tsig_verify_ctx, &dummy_record, &dummy_data[0],
dummy_data.size(), TSIGError::BAD_KEY(),
TSIGContext::RECEIVED_REQUEST);
+ TSIGContext tsig_ctx_copy(*tsig_verify_ctx.get(), Sign);
try {
int dummydata;
isc::util::unittests::force_throw_on_new = true;
isc::util::unittests::throw_size_on_new = sizeof(TSIGRecord);
- tsig_verify_ctx->sign(0, &dummydata, sizeof(dummydata));
+ tsig_ctx_copy.sign(0, &dummydata, sizeof(dummydata));
isc::util::unittests::force_throw_on_new = false;
ASSERT_FALSE(true) << "Expected throw on new, but it didn't happen";
} catch (const std::bad_alloc&) {
isc::util::unittests::force_throw_on_new = false;
// sign() threw, so the state should still be RECEIVED_REQUEST
- EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_verify_ctx->getState());
+ EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_ctx_copy.getState());
}
isc::util::unittests::force_throw_on_new = false;
}
@@ -445,7 +461,7 @@ TEST_F(TSIGTest, signUsingHMACSHA1) {
secret.clear();
decodeBase64("MA+QDhXbyqUak+qnMFyTyEirzng=", secret);
TSIGContext sha1_ctx(TSIGKey(test_name, TSIGKey::HMACSHA1_NAME(),
- &secret[0], secret.size()));
+ &secret[0], secret.size()), Sign);
const uint16_t sha1_qid = 0x0967;
const uint8_t expected_mac[] = {
@@ -467,7 +483,7 @@ TEST_F(TSIGTest, signUsingHMACSHA224) {
secret.clear();
decodeBase64("MA+QDhXbyqUak+qnMFyTyEirzng=", secret);
TSIGContext sha1_ctx(TSIGKey(test_name, TSIGKey::HMACSHA224_NAME(),
- &secret[0], secret.size()));
+ &secret[0], secret.size()), Sign);
const uint16_t sha1_qid = 0x0967;
const uint8_t expected_mac[] = {
@@ -504,9 +520,10 @@ TEST_F(TSIGTest, verifyThenSignResponse) {
}
// Transform the original message to a response, then sign the response
- // with the context of "verified state".
+ // with a copy of the context of "verified state".
+ TSIGContext tsig_ctx_copy(*tsig_verify_ctx.get(), Sign);
ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
- tsig_verify_ctx.get(),
+ &tsig_ctx_copy,
QR_FLAG|AA_FLAG|RD_FLAG,
RRType::A(), "192.0.2.1");
const uint8_t expected_mac[] = {
@@ -587,7 +604,8 @@ TEST_F(TSIGTest, signContinuation) {
}
// Create and sign the first response message
- tsig = createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+ TSIGContext tsig_ctx_copy(*tsig_verify_ctx.get(), Sign);
+ tsig = createMessageAndSign(axfr_qid, zone_name, &tsig_ctx_copy,
AA_FLAG|QR_FLAG, RRType::AXFR(),
"ns.example.com. root.example.com. "
"2011041503 7200 3600 2592000 1200",
@@ -596,9 +614,10 @@ TEST_F(TSIGTest, signContinuation) {
// Then verify it at the requester side.
received_data.clear();
UnitTestUtil::readWireData("tsig_verify2.wire", received_data);
+ TSIGContext tsig_ctx_copy2(*tsig_ctx.get(), Verify);
{
SCOPED_TRACE("Verify first AXFR response");
- commonVerifyChecks(*tsig_ctx, tsig.get(), &received_data[0],
+ commonVerifyChecks(tsig_ctx_copy2, tsig.get(), &received_data[0],
received_data.size(), TSIGError::NOERROR());
}
@@ -609,7 +628,7 @@ TEST_F(TSIGTest, signContinuation) {
};
{
SCOPED_TRACE("Sign test for continued response in TCP stream");
- tsig = createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+ tsig = createMessageAndSign(axfr_qid, zone_name, &tsig_ctx_copy,
AA_FLAG|QR_FLAG, RRType::AXFR(),
"ns.example.com.", &RRType::NS(), false);
commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac,
@@ -621,7 +640,7 @@ TEST_F(TSIGTest, signContinuation) {
UnitTestUtil::readWireData("tsig_verify3.wire", received_data);
{
SCOPED_TRACE("Verify second AXFR response");
- commonVerifyChecks(*tsig_ctx, tsig.get(), &received_data[0],
+ commonVerifyChecks(tsig_ctx_copy2, tsig.get(), &received_data[0],
received_data.size(), TSIGError::NOERROR());
}
}
@@ -657,7 +676,8 @@ TEST_F(TSIGTest, badtimeResponse) {
}
// make and sign a response in the context of TSIG error.
- tsig = createMessageAndSign(test_qid, test_name, tsig_verify_ctx.get(),
+ TSIGContext tsig_ctx_copy(*tsig_verify_ctx.get(), Sign);
+ tsig = createMessageAndSign(test_qid, test_name, &tsig_ctx_copy,
QR_FLAG, RRType::SOA(), NULL, NULL,
true, Rcode::NOTAUTH());
const uint8_t expected_otherdata[] = { 0, 0, 0x4d, 0xa8, 0xbe, 0x86 };
@@ -741,20 +761,22 @@ TEST_F(TSIGTest, badsigResponse) {
// Try to sign a simple message with bogus secret. It should fail
// with BADSIG.
createMessageFromFile("message_toWire2.wire");
- TSIGContext bad_ctx(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(),
- &dummy_data[0], dummy_data.size()));
+ TSIGContext bad_vrfy_ctx(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(),
+ &dummy_data[0], dummy_data.size()),
+ Verify);
{
SCOPED_TRACE("Verify resulting in BADSIG");
- commonVerifyChecks(bad_ctx, message.getTSIGRecord(),
+ commonVerifyChecks(bad_vrfy_ctx, message.getTSIGRecord(),
&received_data[0], received_data.size(),
TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
}
// Sign the same message (which doesn't matter for this test) with the
// context of "checked state".
+ TSIGContext bad_sign_ctx(bad_vrfy_ctx, Sign);
{
SCOPED_TRACE("Sign test for response with BADSIG error");
- commonSignChecks(createMessageAndSign(qid, test_name, &bad_ctx),
+ commonSignChecks(createMessageAndSign(qid, test_name, &bad_sign_ctx),
message.getQid(), 0x4da8877a, NULL, 0,
16); // 16: BADSIG
}
@@ -763,19 +785,22 @@ TEST_F(TSIGTest, badsigResponse) {
TEST_F(TSIGTest, badkeyResponse) {
// A similar test as badsigResponse but for BADKEY
isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
- tsig_ctx.reset(new TestTSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
+ tsig_ctx.reset(new TestTSIGContext(badkey_name, Sign,
+ TSIGKey::HMACMD5_NAME(),
keyring));
+ TSIGContext tsig_ctx_copy(*tsig_ctx.get(), Verify);
{
SCOPED_TRACE("Verify resulting in BADKEY");
- commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
+ commonVerifyChecks(tsig_ctx_copy, &dummy_record, &dummy_data[0],
dummy_data.size(), TSIGError::BAD_KEY(),
TSIGContext::RECEIVED_REQUEST);
}
+ TSIGContext tsig_ctx_copy2(tsig_ctx_copy, Sign);
{
SCOPED_TRACE("Sign test for response with BADKEY error");
ConstTSIGRecordPtr sig = createMessageAndSign(qid, test_name,
- tsig_ctx.get());
+ &tsig_ctx_copy2);
EXPECT_EQ(badkey_name, sig->getName());
commonSignChecks(sig, qid, 0x4da8877a, NULL, 0, 17); // 17: BADKEY
}
@@ -784,9 +809,10 @@ TEST_F(TSIGTest, badkeyResponse) {
TEST_F(TSIGTest, badkeyForResponse) {
// "BADKEY" case for a response to a signed message
createMessageAndSign(qid, test_name, tsig_ctx.get());
+ TSIGContext tsig_ctx_copy(*tsig_ctx.get(), Verify);
{
SCOPED_TRACE("Verify a response resulting in BADKEY");
- commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
+ commonVerifyChecks(tsig_ctx_copy, &dummy_record, &dummy_data[0],
dummy_data.size(), TSIGError::BAD_KEY(),
TSIGContext::SENT_REQUEST);
}
@@ -797,9 +823,10 @@ TEST_F(TSIGTest, badkeyForResponse) {
0x4da8877a,
TSIGContext::DEFAULT_FUDGE,
0, NULL, qid, 0, 0, NULL));
+ TSIGContext tsig_ctx_copy2(*tsig_ctx.get(), Verify);
{
SCOPED_TRACE("Verify a response resulting in BADKEY due to bad alg");
- commonVerifyChecks(*tsig_ctx, &dummy_record2, &dummy_data[0],
+ commonVerifyChecks(tsig_ctx_copy2, &dummy_record2, &dummy_data[0],
dummy_data.size(), TSIGError::BAD_KEY(),
TSIGContext::SENT_REQUEST);
}
@@ -815,9 +842,10 @@ TEST_F(TSIGTest, badsigThenValidate) {
createMessageAndSign(qid, test_name, tsig_ctx.get());
createMessageFromFile("tsig_verify4.wire");
+ TSIGContext tsig_ctx_copy(*tsig_ctx.get(), Verify);
{
SCOPED_TRACE("Verify a response that should fail due to BADSIG");
- commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ commonVerifyChecks(tsig_ctx_copy, message.getTSIGRecord(),
&received_data[0], received_data.size(),
TSIGError::BAD_SIG(), TSIGContext::SENT_REQUEST);
}
@@ -825,7 +853,7 @@ TEST_F(TSIGTest, badsigThenValidate) {
createMessageFromFile("tsig_verify5.wire");
{
SCOPED_TRACE("Verify a response after a BADSIG failure");
- commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ commonVerifyChecks(tsig_ctx_copy, message.getTSIGRecord(),
&received_data[0], received_data.size(),
TSIGError::NOERROR(),
TSIGContext::VERIFIED_RESPONSE);
@@ -839,9 +867,10 @@ TEST_F(TSIGTest, nosigThenValidate) {
createMessageAndSign(qid, test_name, tsig_ctx.get());
+ TSIGContext tsig_ctx_copy(*tsig_ctx.get(), Verify);
{
SCOPED_TRACE("Verify a response without TSIG that should exist");
- commonVerifyChecks(*tsig_ctx, NULL, &dummy_data[0],
+ commonVerifyChecks(tsig_ctx_copy, NULL, &dummy_data[0],
dummy_data.size(), TSIGError::FORMERR(),
TSIGContext::SENT_REQUEST, true);
}
@@ -849,7 +878,7 @@ TEST_F(TSIGTest, nosigThenValidate) {
createMessageFromFile("tsig_verify5.wire");
{
SCOPED_TRACE("Verify a response after a FORMERR failure");
- commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ commonVerifyChecks(tsig_ctx_copy, message.getTSIGRecord(),
&received_data[0], received_data.size(),
TSIGError::NOERROR(),
TSIGContext::VERIFIED_RESPONSE);
@@ -862,12 +891,13 @@ TEST_F(TSIGTest, badtimeThenValidate) {
ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
tsig_ctx.get());
+ TSIGContext tsig_ctx_copy(*tsig_ctx.get(), Verify);
// "advance the clock" and try validating, which should fail due to BADTIME
isc::util::detail::gettimeFunction = testGetTime<0x4da8877a + 600>;
{
SCOPED_TRACE("Verify resulting in BADTIME due to expired SIG");
- commonVerifyChecks(*tsig_ctx, tsig.get(), &dummy_data[0],
+ commonVerifyChecks(tsig_ctx_copy, tsig.get(), &dummy_data[0],
dummy_data.size(), TSIGError::BAD_TIME(),
TSIGContext::SENT_REQUEST);
}
@@ -877,7 +907,7 @@ TEST_F(TSIGTest, badtimeThenValidate) {
createMessageFromFile("tsig_verify5.wire");
{
SCOPED_TRACE("Verify a response after a BADTIME failure");
- commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ commonVerifyChecks(tsig_ctx_copy, message.getTSIGRecord(),
&received_data[0], received_data.size(),
TSIGError::NOERROR(),
TSIGContext::VERIFIED_RESPONSE);
@@ -918,15 +948,17 @@ TEST_F(TSIGTest, verifyAfterSendResponse) {
tsig_verify_ctx->verify(message.getTSIGRecord(), &received_data[0],
received_data.size());
EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_verify_ctx->getState());
- createMessageAndSign(qid, test_name, tsig_verify_ctx.get(),
+ TSIGContext tsig_ctx_copy(*tsig_verify_ctx.get(), Sign);
+ createMessageAndSign(qid, test_name, &tsig_ctx_copy,
QR_FLAG|AA_FLAG|RD_FLAG, RRType::A(), "192.0.2.1");
- EXPECT_EQ(TSIGContext::SENT_RESPONSE, tsig_verify_ctx->getState());
+ EXPECT_EQ(TSIGContext::SENT_RESPONSE, tsig_ctx_copy.getState());
// Now trying further verification.
createMessageFromFile("message_toWire2.wire");
- EXPECT_THROW(tsig_verify_ctx->verify(message.getTSIGRecord(),
- &received_data[0],
- received_data.size()),
+ TSIGContext tsig_ctx_copy2(tsig_ctx_copy, Verify);
+ EXPECT_THROW(tsig_ctx_copy2.verify(message.getTSIGRecord(),
+ &received_data[0],
+ received_data.size()),
TSIGContextError);
}
@@ -939,12 +971,14 @@ TEST_F(TSIGTest, signAfterVerified) {
isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
createMessageAndSign(qid, test_name, tsig_ctx.get());
createMessageFromFile("tsig_verify5.wire");
- tsig_ctx->verify(message.getTSIGRecord(), &received_data[0],
- received_data.size());
- EXPECT_EQ(TSIGContext::VERIFIED_RESPONSE, tsig_ctx->getState());
+ TSIGContext tsig_ctx_copy(*tsig_ctx.get(), Verify);
+ tsig_ctx_copy.verify(message.getTSIGRecord(), &received_data[0],
+ received_data.size());
+ EXPECT_EQ(TSIGContext::VERIFIED_RESPONSE, tsig_ctx_copy.getState());
// Now trying further signing.
- EXPECT_THROW(createMessageAndSign(qid, test_name, tsig_ctx.get()),
+ TSIGContext tsig_ctx_copy2(tsig_ctx_copy, Sign);
+ EXPECT_THROW(createMessageAndSign(qid, test_name, &tsig_ctx_copy2),
TSIGContextError);
}
@@ -975,67 +1009,77 @@ TEST_F(TSIGTest, getTSIGLength) {
// hmac-sha1: n2=11, x=20
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA1_NAME(),
- &dummy_data[0], 20)));
+ &dummy_data[0], 20),
+ Sign));
EXPECT_EQ(74, tsig_ctx->getTSIGLength());
// hmac-sha256: n2=13, x=32
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA256_NAME(),
- &dummy_data[0], 32)));
+ &dummy_data[0], 32),
+ Sign));
EXPECT_EQ(88, tsig_ctx->getTSIGLength());
// hmac-sha224: n2=13, x=28
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA224_NAME(),
- &dummy_data[0], 28)));
+ &dummy_data[0], 28),
+ Sign));
EXPECT_EQ(84, tsig_ctx->getTSIGLength());
// hmac-sha384: n2=13, x=48
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA384_NAME(),
- &dummy_data[0], 48)));
+ &dummy_data[0], 48),
+ Sign));
EXPECT_EQ(104, tsig_ctx->getTSIGLength());
// hmac-sha512: n2=13, x=64
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA512_NAME(),
- &dummy_data[0], 64)));
+ &dummy_data[0], 64),
+ Sign));
EXPECT_EQ(120, tsig_ctx->getTSIGLength());
// bad key case: n1=len(badkey.example.com)=20, n2=26, x=0
- tsig_ctx.reset(new TestTSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
+ tsig_ctx.reset(new TestTSIGContext(badkey_name,
+ Sign,
+ TSIGKey::HMACMD5_NAME(),
keyring));
EXPECT_EQ(72, tsig_ctx->getTSIGLength());
// bad sig case: n1=17, n2=26, x=0
isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
createMessageFromFile("message_toWire2.wire");
- tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
- TSIGKey::HMACMD5_NAME(),
- &dummy_data[0],
- dummy_data.size())));
+ tsig_verify_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &dummy_data[0],
+ dummy_data.size()),
+ Verify));
{
SCOPED_TRACE("Verify resulting in BADSIG");
- commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
&received_data[0], received_data.size(),
- TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+ TSIGError::BAD_SIG(),
+ TSIGContext::RECEIVED_REQUEST);
}
- EXPECT_EQ(69, tsig_ctx->getTSIGLength());
+ EXPECT_EQ(69, tsig_verify_ctx->getTSIGLength());
// bad time case: n1=17, n2=26, x=16, y=6
isc::util::detail::gettimeFunction = testGetTime<0x4da8877a - 1000>;
- tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
- TSIGKey::HMACMD5_NAME(),
- &dummy_data[0],
- dummy_data.size())));
+ tsig_verify_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &dummy_data[0],
+ dummy_data.size()),
+ Verify));
{
SCOPED_TRACE("Verify resulting in BADTIME");
- commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
&received_data[0], received_data.size(),
TSIGError::BAD_TIME(),
TSIGContext::RECEIVED_REQUEST);
}
- EXPECT_EQ(91, tsig_ctx->getTSIGLength());
+ EXPECT_EQ(91, tsig_verify_ctx->getTSIGLength());
}
// Verify a stream of multiple messages. Some of them have a signature omitted.
@@ -1049,11 +1093,15 @@ TEST_F(TSIGTest, verifyMulti) {
{
SCOPED_TRACE("Query");
ConstTSIGRecordPtr tsig = createMessageAndSign(1234, test_name,
- tsig_verify_ctx.get());
- commonVerifyChecks(*tsig_ctx, tsig.get(),
+ tsig_ctx.get());
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(),
renderer.getData(), renderer.getLength(),
TSIGError(Rcode::NOERROR()),
TSIGContext::RECEIVED_REQUEST);
+ TSIGContext tsig_ctx_copy(*tsig_ctx.get(), Verify);
+ TestTSIGContext tsig_ctx_copy2(*tsig_verify_ctx.get(), Sign);
+ tsig_ctx.reset(new TestTSIGContext(tsig_ctx_copy2, Sign));
+ tsig_verify_ctx.reset(new TSIGContext(tsig_ctx_copy, Verify));
}
{
diff --git a/src/lib/dns/tsig.cc b/src/lib/dns/tsig.cc
index d7ffcf8..2cce454 100644
--- a/src/lib/dns/tsig.cc
+++ b/src/lib/dns/tsig.cc
@@ -59,10 +59,11 @@ getTSIGTime() {
struct TSIGContext::TSIGContextImpl {
TSIGContextImpl(const TSIGKey& key,
+ const Operation operation,
TSIGError error = TSIGError::NOERROR()) :
state_(INIT), key_(key), error_(error),
previous_timesigned_(0), digest_len_(0),
- last_sig_dist_(-1)
+ last_sig_dist_(-1), op_(operation)
{
if (error == TSIGError::NOERROR()) {
// In normal (NOERROR) case, the key should be valid, and we
@@ -77,7 +78,7 @@ struct TSIGContext::TSIGContextImpl {
try {
hmac_.reset(CryptoLink::getCryptoLink().createHMAC(
key_.getSecret(), key_.getSecretLength(),
- key_.getAlgorithm()),
+ operation, key_.getAlgorithm()),
deleteHMAC);
} catch (const Exception&) {
return;
@@ -86,6 +87,25 @@ struct TSIGContext::TSIGContextImpl {
}
}
+ // Copy constructor
+ TSIGContextImpl(const TSIGContextImpl& other,
+ const Operation operation) :
+ state_(other.state_), key_(other.key_),
+ previous_digest_(other.previous_digest_), error_(other.error_),
+ previous_timesigned_(other.previous_timesigned_), digest_len_(0),
+ last_sig_dist_(-1), op_(operation)
+ {
+ try {
+ hmac_.reset(CryptoLink::getCryptoLink().createHMAC(
+ key_.getSecret(), key_.getSecretLength(),
+ operation, key_.getAlgorithm()),
+ deleteHMAC);
+ } catch (const Exception&) {
+ return;
+ }
+ digest_len_ = hmac_->getOutputLength();
+ }
+
// This helper method is used from verify(). It's expected to be called
// just before verify() returns. It updates internal state based on
// the verification result and return the TSIGError to be returned to
@@ -113,7 +133,7 @@ struct TSIGContext::TSIGContextImpl {
// create a new one and return it. In the former case, the ownership is
// transferred to the caller; the stored HMAC will be reset after the
// call.
- HMACPtr createHMAC() {
+ HMACPtr createHMAC(const Operation operation) {
if (hmac_) {
HMACPtr ret = HMACPtr();
ret.swap(hmac_);
@@ -121,7 +141,7 @@ struct TSIGContext::TSIGContextImpl {
}
return (HMACPtr(CryptoLink::getCryptoLink().createHMAC(
key_.getSecret(), key_.getSecretLength(),
- key_.getAlgorithm()),
+ operation, key_.getAlgorithm()),
deleteHMAC));
}
@@ -157,6 +177,8 @@ struct TSIGContext::TSIGContextImpl {
// means the last message was signed. Special value -1 means there was no
// signed message yet.
int last_sig_dist_;
+ // Need for update()
+ const Operation op_;
};
void
@@ -259,11 +281,19 @@ TSIGContext::TSIGContextImpl::digestDNSMessage(HMACPtr hmac,
hmac->update(msgptr, data_len - MESSAGE_HEADER_LEN);
}
-TSIGContext::TSIGContext(const TSIGKey& key) : impl_(new TSIGContextImpl(key))
+TSIGContext::TSIGContext(const TSIGKey& key, const Operation operation) :
+ impl_(new TSIGContextImpl(key, operation))
+{
+}
+
+TSIGContext::TSIGContext(const TSIGContext& other, const Operation operation) :
+ impl_(new TSIGContextImpl(*other.impl_, operation))
{
}
-TSIGContext::TSIGContext(const Name& key_name, const Name& algorithm_name,
+TSIGContext::TSIGContext(const Name& key_name,
+ const Operation operation,
+ const Name& algorithm_name,
const TSIGKeyRing& keyring) : impl_(NULL)
{
const TSIGKeyRing::FindResult result(keyring.find(key_name,
@@ -274,9 +304,11 @@ TSIGContext::TSIGContext(const Name& key_name, const Name& algorithm_name,
// be used in subsequent response with a TSIG indicating a BADKEY
// error.
impl_ = new TSIGContextImpl(TSIGKey(key_name, algorithm_name,
- NULL, 0), TSIGError::BAD_KEY());
+ NULL, 0),
+ operation,
+ TSIGError::BAD_KEY());
} else {
- impl_ = new TSIGContextImpl(*result.key);
+ impl_ = new TSIGContextImpl(*result.key, operation);
}
}
@@ -367,7 +399,7 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
return (tsig);
}
- HMACPtr hmac(impl_->createHMAC());
+ HMACPtr hmac(impl_->createHMAC(Sign));
// If the context has previous MAC (either the Request MAC or its own
// previous MAC), digest it.
@@ -506,7 +538,7 @@ TSIGContext::verify(const TSIGRecord* const record, const void* const data,
return (impl_->postVerifyUpdate(error, NULL, 0));
}
- HMACPtr hmac(impl_->createHMAC());
+ HMACPtr hmac(impl_->createHMAC(Verify));
// If the context has previous MAC (either the Request MAC or its own
// previous MAC), digest it.
@@ -555,7 +587,8 @@ TSIGContext::lastHadSignature() const {
void
TSIGContext::update(const void* const data, size_t len) {
- HMACPtr hmac(impl_->createHMAC());
+ // Inherit the operation or fail
+ HMACPtr hmac(impl_->createHMAC(impl_->op_));
// Use the previous digest and never use it again
impl_->digestPreviousMAC(hmac);
impl_->previous_digest_.clear();
diff --git a/src/lib/dns/tsig.h b/src/lib/dns/tsig.h
index 9ccc580..18a8888 100644
--- a/src/lib/dns/tsig.h
+++ b/src/lib/dns/tsig.h
@@ -15,8 +15,6 @@
#ifndef __TSIG_H
#define __TSIG_H 1
-#include <boost/noncopyable.hpp>
-
#include <exceptions/exceptions.h>
#include <dns/tsigerror.h>
@@ -90,7 +88,8 @@ public:
/// \code
/// // "renderer" is of MessageRenderer to render the message.
/// // (TSIGKey would be configured from config or command line in real app)
-/// TSIGContext ctx(TSIGKey("key.example:MSG6Ng=="));
+/// TSIGContext ctx(TSIGKey("key.example:MSG6Ng==",
+/// isc::cryptolink::Verify));
/// Message message(Message::RENDER);
/// message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
/// RRType::A()));
@@ -130,7 +129,9 @@ public:
///
/// const TSIGRecord* tsig = message.getTSIGRecord();
/// if (tsig != NULL) {
-/// TSIGContext ctx(tsig->getName(), tsig->getRdata().getAlgorithm(),
+/// TSIGContext ctx(tsig->getName(),
+/// isc::cryptolink::Verify,
+/// tsig->getRdata().getAlgorithm(),
/// keyring);
/// ctx.verify(tsig, data, data_len);
///
@@ -161,6 +162,7 @@ public:
/// typical usage as described above. But there is no strong technical
/// reason why this class cannot be copyable. If we see the need for it
/// in future we may change the implementation on this point.
+/// Changed to support crypto operations, i.e., verify <-> sign.
///
/// <b>Note to developers:</b>
/// One basic design choice is to make the \c TSIGContext class is as
@@ -172,7 +174,7 @@ public:
/// direct or indirect dependencies. The interface of \c sign() that takes
/// opaque data (instead of, e.g., a \c Message or \c MessageRenderer object)
/// is therefore a deliberate design decision.
-class TSIGContext : boost::noncopyable {
+class TSIGContext {
public:
/// Internal state of context
///
@@ -198,14 +200,21 @@ public:
/// \exception std::bad_alloc Resource allocation for internal data fails
///
/// \param key The TSIG key to be used for TSIG sessions with this context.
- explicit TSIGContext(const TSIGKey& key);
+ TSIGContext(const TSIGKey& key,
+ const isc::cryptolink::Operation operation);
/// Constructor from key parameters and key ring.
- TSIGContext(const Name& key_name, const Name& algorithm_name,
+ TSIGContext(const Name& key_name,
+ const isc::cryptolink::Operation operation,
+ const Name& algorithm_name,
const TSIGKeyRing& keyring);
/// The destructor.
~TSIGContext();
+
+ /// Copy contructor.
+ TSIGContext(const TSIGContext& other,
+ const isc::cryptolink::Operation operation);
//@}
/// Sign a DNS message.
diff --git a/src/lib/python/isc/ddns/tests/session_tests.py b/src/lib/python/isc/ddns/tests/session_tests.py
index f7c2d3c..11285ed 100644
--- a/src/lib/python/isc/ddns/tests/session_tests.py
+++ b/src/lib/python/isc/ddns/tests/session_tests.py
@@ -53,7 +53,7 @@ def create_update_msg(zones=[TEST_ZONE_RECORD], prerequisites=[],
renderer = MessageRenderer()
if tsig_key is not None:
- msg.to_wire(renderer, TSIGContext(tsig_key))
+ msg.to_wire(renderer, TSIGContext(tsig_key, TSIGContext.SIGN))
else:
msg.to_wire(renderer)
diff --git a/src/lib/python/isc/testutils/tsigctx_mock.py b/src/lib/python/isc/testutils/tsigctx_mock.py
index 0158987..86ef139 100644
--- a/src/lib/python/isc/testutils/tsigctx_mock.py
+++ b/src/lib/python/isc/testutils/tsigctx_mock.py
@@ -25,8 +25,8 @@ class MockTSIGContext(TSIGContext):
TSIGError object.
"""
- def __init__(self, tsig_key):
- super().__init__(tsig_key)
+ def __init__(self, tsig_key, operation):
+ super().__init__(tsig_key, operation)
self.error = None
self.verify_called = 0 # number of verify() called
More information about the bind10-changes
mailing list