Commit c3c19155 authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner

[1357] Internal TSIGContext::update method

To be used in the case when there's a message without TSIG in the middle
of signed stream. Also used in tests for now.
parent 1f5426f7
......@@ -66,6 +66,22 @@ testGetTime() {
return (NOW);
}
// Thin wrapper around TSIGContext to allow access to the
// update method.
class TestTSIGContext : public TSIGContext {
public:
TestTSIGContext(const TSIGKey& key) :
TSIGContext(key)
{}
TestTSIGContext(const Name& key_name, const Name& algorithm_name,
const TSIGKeyRing& keyring) :
TSIGContext(key_name, algorithm_name, keyring)
{}
void update(const void* const data, size_t len) {
TSIGContext::update(data, len);
}
};
class TSIGTest : public ::testing::Test {
protected:
TSIGTest() :
......@@ -83,9 +99,10 @@ protected:
isc::util::detail::gettimeFunction = NULL;
decodeBase64("SFuWd/q99SzF8Yzd1QbB9g==", secret);
tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
TSIGKey::HMACMD5_NAME(),
&secret[0], secret.size())));
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACMD5_NAME(),
&secret[0],
secret.size())));
tsig_verify_ctx.reset(new TSIGContext(TSIGKey(test_name,
TSIGKey::HMACMD5_NAME(),
&secret[0],
......@@ -116,7 +133,7 @@ protected:
static const unsigned int AA_FLAG = 0x2;
static const unsigned int RD_FLAG = 0x4;
boost::scoped_ptr<TSIGContext> tsig_ctx;
boost::scoped_ptr<TestTSIGContext> tsig_ctx;
boost::scoped_ptr<TSIGContext> tsig_verify_ctx;
TSIGKeyRing keyring;
const uint16_t qid;
......@@ -746,8 +763,8 @@ 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 TSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
keyring));
tsig_ctx.reset(new TestTSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
keyring));
{
SCOPED_TRACE("Verify resulting in BADKEY");
commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
......@@ -956,45 +973,47 @@ TEST_F(TSIGTest, getTSIGLength) {
EXPECT_EQ(85, tsig_ctx->getTSIGLength());
// hmac-sha1: n2=11, x=20
tsig_ctx.reset(new TSIGContext(TSIGKey(test_name, TSIGKey::HMACSHA1_NAME(),
&dummy_data[0], 20)));
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA1_NAME(),
&dummy_data[0], 20)));
EXPECT_EQ(74, tsig_ctx->getTSIGLength());
// hmac-sha256: n2=13, x=32
tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA256_NAME(),
&dummy_data[0], 32)));
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA256_NAME(),
&dummy_data[0], 32)));
EXPECT_EQ(88, tsig_ctx->getTSIGLength());
// hmac-sha224: n2=13, x=28
tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA224_NAME(),
&dummy_data[0], 28)));
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA224_NAME(),
&dummy_data[0], 28)));
EXPECT_EQ(84, tsig_ctx->getTSIGLength());
// hmac-sha384: n2=13, x=48
tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA384_NAME(),
&dummy_data[0], 48)));
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA384_NAME(),
&dummy_data[0], 48)));
EXPECT_EQ(104, tsig_ctx->getTSIGLength());
// hmac-sha512: n2=13, x=64
tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA512_NAME(),
&dummy_data[0], 64)));
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACSHA512_NAME(),
&dummy_data[0], 64)));
EXPECT_EQ(120, tsig_ctx->getTSIGLength());
// bad key case: n1=len(badkey.example.com)=20, n2=26, x=0
tsig_ctx.reset(new TSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
keyring));
tsig_ctx.reset(new TestTSIGContext(badkey_name, 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 TSIGContext(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(),
&dummy_data[0],
dummy_data.size())));
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACMD5_NAME(),
&dummy_data[0],
dummy_data.size())));
{
SCOPED_TRACE("Verify resulting in BADSIG");
commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
......@@ -1005,9 +1024,10 @@ TEST_F(TSIGTest, getTSIGLength) {
// bad time case: n1=17, n2=26, x=16, y=6
isc::util::detail::gettimeFunction = testGetTime<0x4da8877a - 1000>;
tsig_ctx.reset(new TSIGContext(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(),
&dummy_data[0],
dummy_data.size())));
tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
TSIGKey::HMACMD5_NAME(),
&dummy_data[0],
dummy_data.size())));
{
SCOPED_TRACE("Verify resulting in BADTIME");
commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
......@@ -1059,7 +1079,11 @@ TEST_F(TSIGTest, verifyMulti) {
answer_rrset->addRdata(createRdata(RRType::A(), test_class,
"192.0.2.1"));
message.addRRset(Message::SECTION_ANSWER, answer_rrset);
message.toWire(renderer, *tsig_ctx);
message.toWire(renderer);
// Update the internal state. We abuse the knowledge of
// internals here a little bit to generate correct test data
tsig_ctx->update(renderer.getData(), renderer.getLength());
commonVerifyChecks(*tsig_verify_ctx, NULL,
renderer.getData(), renderer.getLength(),
TSIGError(Rcode::NOERROR()),
......
......@@ -138,7 +138,7 @@ struct TSIGContext::TSIGContextImpl {
// performance bottleneck, we could have this class a buffer as a member
// variable and reuse it throughout the object's lifetime. Right now,
// we prefer keeping the scope for local things as small as possible.
void digestPreviousMAC(HMACPtr hmac) const;
void digestPreviousMAC(HMACPtr hmac);
void digestTSIGVariables(HMACPtr hmac, uint16_t rrclass, uint32_t rrttl,
uint64_t time_signed, uint16_t fudge,
uint16_t error, uint16_t otherlen,
......@@ -160,11 +160,18 @@ struct TSIGContext::TSIGContextImpl {
};
void
TSIGContext::TSIGContextImpl::digestPreviousMAC(HMACPtr hmac) const {
TSIGContext::TSIGContextImpl::digestPreviousMAC(HMACPtr hmac) {
// We should have ensured the digest size fits 16 bits within this class
// implementation.
assert(previous_digest_.size() <= 0xffff);
if (previous_digest_.empty()) {
// The previous digest was already used. We're in the middle of
// TCP stream somewhere and we already pushed some unsigned message
// into the HMAC state.
return;
}
OutputBuffer buffer(sizeof(uint16_t) + previous_digest_.size());
const uint16_t previous_digest_len(previous_digest_.size());
buffer.writeUint16(previous_digest_len);
......@@ -536,5 +543,16 @@ TSIGContext::lastHadSignature() const {
return (impl_->last_sig_dist_ == 0);
}
void
TSIGContext::update(const void* const data, size_t len) {
HMACPtr hmac(impl_->createHMAC());
// Use the previous digest and never use it again
impl_->digestPreviousMAC(hmac);
impl_->previous_digest_.clear();
// Push the message there
hmac->update(data, len);
impl_->hmac_ = hmac;
}
} // namespace dns
} // namespace isc
......@@ -413,6 +413,19 @@ public:
static const uint16_t DEFAULT_FUDGE = 300;
//@}
protected:
/// \brief Update internal HMAC state by more data.
///
/// This is used mostly internaly, when we need to verify a message without
/// TSIG signature in the middle of signed TCP stream. However, it is also
/// used in tests, so it's protected instead of private, to allow tests
/// in.
///
/// It doesn't contain sanity checks, and it is not tested directly. But
/// we may want to add these one day to allow generating the skipped TSIG
/// messages too. Until then, do not use this method.
void update(const void* const data, size_t len);
private:
struct TSIGContextImpl;
TSIGContextImpl* impl_;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment