// *********************** TSIGKeyInfo *************************
+const char* TSIGKeyInfo::MD5_STR = "MD5";
+const char* TSIGKeyInfo::SHA1_STR = "SHA1";
+const char* TSIGKeyInfo::SHA224_STR = "SHA224";
+const char* TSIGKeyInfo::SHA256_STR = "SHA256";
+const char* TSIGKeyInfo::SHA384_STR = "SHA384";
+const char* TSIGKeyInfo::SHA512_STR = "SHA512";
+
TSIGKeyInfo::TSIGKeyInfo(const std::string& name, const std::string& algorithm,
const std::string& secret)
- :name_(name), algorithm_(algorithm), secret_(secret) {
+ :name_(name), algorithm_(algorithm), secret_(secret), tsig_key_() {
+ remakeKey();
}
TSIGKeyInfo::~TSIGKeyInfo() {
}
+const dns::Name&
+TSIGKeyInfo::stringToAlgorithmName(const std::string& algorithm_id) {
+ if (boost::iequals(algorithm_id, MD5_STR)) {
+ return (dns::TSIGKey::HMACMD5_NAME());
+ }
+ if (boost::iequals(algorithm_id, SHA1_STR)) {
+ return (dns::TSIGKey::HMACSHA1_NAME());
+ }
+ if (boost::iequals(algorithm_id, SHA224_STR)) {
+ return (dns::TSIGKey::HMACSHA224_NAME());
+ }
+ if (boost::iequals(algorithm_id, SHA256_STR)) {
+ return (dns::TSIGKey::HMACSHA256_NAME());
+ }
+ if (boost::iequals(algorithm_id, SHA384_STR)) {
+ return (dns::TSIGKey::HMACSHA384_NAME());
+ }
+ if (boost::iequals(algorithm_id, SHA512_STR)) {
+ return (dns::TSIGKey::HMACSHA512_NAME());
+ }
+
+ isc_throw(BadValue, "Unknown TSIG Key algorithm:" << algorithm_id);
+}
+
+void
+TSIGKeyInfo::remakeKey() {
+ try {
+ tsig_key_.reset(new dns::TSIGKey(dns::Name(name_),
+ stringToAlgorithmName(algorithm_),
+ secret_.c_str(), secret_.size()));
+ } catch (const std::exception& ex) {
+ isc_throw(D2CfgError, "Cannot make TSIGKey: " << ex.what());
+ }
+}
// *********************** DnsServerInfo *************************
local_scalars_.getParam("algorithm", algorithm);
local_scalars_.getParam("secret", secret);
- // @todo Validation here is very superficial. This will expand as TSIG
- // Key use is more fully implemented.
-
// Name cannot be blank.
if (name.empty()) {
isc_throw(D2CfgError, "TSIG Key Info must specify name");
void
TSIGKeyInfoParser::commit() {
- /// @todo if at some point TSIG keys need some form of runtime resource
- /// initialization, such as creating some sort of hash instance in
- /// crytpolib. Once TSIG is fully implemented under Trac #3432 we'll know.
}
// *********************** TSIGKeyInfoListParser *************************
#include <d2/d2_asio.h>
#include <d2/d_cfg_mgr.h>
#include <dhcpsrv/dhcp_parsers.h>
+#include <dns/tsig.h>
#include <exceptions/exceptions.h>
#include <boost/foreach.hpp>
/// @brief Represents a TSIG Key.
///
-/// Currently, this is simple storage class containing the basic attributes of
-/// a TSIG Key. It is intended primarily as a reference for working with
-/// actual keys and may eventually be replaced by isc::dns::TSIGKey. TSIG Key
-/// functionality at this stage is strictly limited to configuration parsing.
-/// @todo full functionality for using TSIG during DNS updates will be added
-/// in a future release.
+/// Acts as both a storage class containing the basic attributes which
+/// describe a TSIG Key, as well as owning and providing access to an
+/// instance of the actual key (@ref isc::dns::TSIGKey) that can be used
+/// by the IO layer for signing and verifying messages.
+///
class TSIGKeyInfo {
public:
+ /// @brief Defines string values for the supported TSIG algorithms
+ //@{
+ static const char* MD5_STR;
+ static const char* SHA1_STR;
+ static const char* SHA256_STR;
+ static const char* SHA224_STR;
+ static const char* SHA384_STR;
+ static const char* SHA512_STR;
+ //}@
/// @brief Constructor
///
/// @param name the unique label used to identify this key
- /// @param algorithm the name of the encryption alogirthm this key uses.
- /// (@todo This will be a fixed list of choices)
+ /// @param algorithm the id of the encryption alogirthm this key uses.
+ /// Currently supported values are (case insensitive):
+ /// -# "MD5"
+ /// -# "SHA1"
+ /// -# "SHA224"
+ /// -# "SHA256"
+ /// -# "SHA384"
+ /// -# "SHA512"
///
/// @param secret the secret component of this key
+ /// @throw D2CfgError if values supplied are invalid:
+ /// name cannot be blank, algorithm must be a supported value,
+ /// secret cannot be blank
TSIGKeyInfo(const std::string& name, const std::string& algorithm,
const std::string& secret);
return (name_);
}
- /// @brief Getter which returns the key's algorithm.
+ /// @brief Getter which returns the key's algorithm string ID
///
/// @return returns the algorithm as as std::string.
const std::string getAlgorithm() const {
return (secret_);
}
+ /// @brief Getter which returns the TSIG key used to sign and verify
+ /// messages
+ ///
+ /// @return const pointer reference to dns::TSIGKey.
+ const dns::TSIGKeyPtr& getTSIGKey() const {
+ return (tsig_key_);
+ }
+
+ /// @brief Converts algorithm id to dns::TSIGKey algorithm dns::Name
+ ///
+ /// @param algorithm_id string value to translate into an algorithm name.
+ /// Currently supported values are (case insensitive):
+ /// -# "MD5"
+ /// -# "SHA1"
+ /// -# "SHA224"
+ /// -# "SHA256"
+ /// -# "SHA384"
+ /// -# "SHA512"
+ ///
+ /// @return const reference to a dns::Name containing the alogorithm name
+ /// @throw BadValue if ID isn't recognized.
+ static const dns::Name& stringToAlgorithmName(const std::string&
+ algorithm_id);
+
private:
+ /// @brief Creates the actual TSIG key instance member
+ ///
+ /// Replaces this tsig_key member with a key newly created using the key
+ /// name, algorithm id, and secret.
+ /// This method is currently only called by the constructor, however it
+ /// could be called post-construction should keys ever support expiration.
+ ///
+ /// @throw D2CfgError with an explanation if the key could not be created.
+ void remakeKey();
+
/// @brief The name of the key.
///
/// This value is the unique identifier that domains use to
/// to specify which TSIG key they need.
std::string name_;
- /// @brief The algorithm that should be used for this key.
+ /// @brief The string ID of the algorithm that should be used for this key.
std::string algorithm_;
/// @brief The secret value component of this key.
std::string secret_;
+
+ /// @brief The actual TSIG key.
+ dns::TSIGKeyPtr tsig_key_;
};
/// @brief Defines a pointer for TSIGKeyInfo instances.
result = false;
}
+ if (!key->getTSIGKey()) {
+ EXPECT_TRUE (key->getTSIGKey());
+ return false;
+ }
+
return (result);
}
// Config with a blank name entry.
std::string config = "{"
" \"name\": \"\" , "
- " \"algorithm\": \"md5\" , "
+ " \"algorithm\": \"MD5\" , "
" \"secret\": \"0123456789\" "
"}";
ASSERT_TRUE(fromJSON(config));
// Verify that build fails on blank algorithm.
EXPECT_THROW(parser_->build(config_set_), D2CfgError);
+ // Config with an invalid algorithm entry.
+ config = "{"
+ " \"name\": \"d2_key_one\" , "
+ " \"algorithm\": \"bogus\" , "
+ " \"secret\": \"0123456789\" "
+ "}";
+
+ ASSERT_TRUE(fromJSON(config));
+
+ // Verify that build fails on blank algorithm.
+ EXPECT_THROW(parser_->build(config_set_), D2CfgError);
+
+
// Config with a blank secret entry.
config = "{"
" \"name\": \"d2_key_one\" , "
- " \"algorithm\": \"md5\" , "
+ " \"algorithm\": \"MD5\" , "
" \"secret\": \"\" "
"}";
// Valid entries for TSIG key, all items are required.
std::string config = "{"
" \"name\": \"d2_key_one\" , "
- " \"algorithm\": \"md5\" , "
+ " \"algorithm\": \"MD5\" , "
" \"secret\": \"0123456789\" "
"}";
ASSERT_TRUE(fromJSON(config));
TSIGKeyInfoPtr& key = gotit->second;
// Verify the key contents.
- EXPECT_TRUE(checkKey(key, "d2_key_one", "md5", "0123456789"));
+ EXPECT_TRUE(checkKey(key, "d2_key_one", "MD5", "0123456789"));
}
/// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
std::string config = "["
" { \"name\": \"key1\" , "
- " \"algorithm\": \"algo1\" ,"
+ " \"algorithm\": \"MD5\" ,"
" \"secret\": \"secret11\" "
" },"
" { \"name\": \"key2\" , "
" \"secret\": \"secret12\" "
" },"
" { \"name\": \"key3\" , "
- " \"algorithm\": \"algo3\" ,"
+ " \"algorithm\": \"MD5\" ,"
" \"secret\": \"secret13\" "
" }"
" ]";
std::string config = "["
" { \"name\": \"key1\" , "
- " \"algorithm\": \"algo1\" ,"
+ " \"algorithm\": \"MD5\" ,"
" \"secret\": \"secret11\" "
" },"
" { \"name\": \"key2\" , "
- " \"algorithm\": \"algo2\" ,"
+ " \"algorithm\": \"MD5\" ,"
" \"secret\": \"secret12\" "
" },"
" { \"name\": \"key1\" , "
- " \"algorithm\": \"algo3\" ,"
+ " \"algorithm\": \"MD5\" ,"
" \"secret\": \"secret13\" "
" }"
" ]";
}
/// @brief Verifies a valid list of TSIG Keys parses correctly.
+/// Also verifies that all of the supported algorithm names work.
TEST_F(TSIGKeyInfoTest, validTSIGKeyList) {
// Construct a valid list of keys.
std::string config = "["
" { \"name\": \"key1\" , "
- " \"algorithm\": \"algo1\" ,"
+ " \"algorithm\": \"MD5\" ,"
" \"secret\": \"secret1\" "
" },"
" { \"name\": \"key2\" , "
- " \"algorithm\": \"algo2\" ,"
+ " \"algorithm\": \"SHA1\" ,"
" \"secret\": \"secret2\" "
" },"
" { \"name\": \"key3\" , "
- " \"algorithm\": \"algo3\" ,"
+ " \"algorithm\": \"SHA256\" ,"
" \"secret\": \"secret3\" "
+ " },"
+ " { \"name\": \"key4\" , "
+ " \"algorithm\": \"SHA224\" ,"
+ " \"secret\": \"secret4\" "
+ " },"
+ " { \"name\": \"key5\" , "
+ " \"algorithm\": \"SHA384\" ,"
+ " \"secret\": \"secret5\" "
+ " },"
+ " { \"name\": \"key6\" , "
+ " \"algorithm\": \"SHA512\" ,"
+ " \"secret\": \"secret6\" "
" }"
" ]";
// Verify the correct number of keys are present
int count = keys_->size();
- ASSERT_EQ(3, count);
+ ASSERT_EQ(6, count);
// Find the 1st key and retrieve it.
TSIGKeyInfoMap::iterator gotit = keys_->find("key1");
TSIGKeyInfoPtr& key = gotit->second;
// Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key1", "algo1", "secret1"));
+ EXPECT_TRUE(checkKey(key, "key1", TSIGKeyInfo::MD5_STR, "secret1"));
// Find the 2nd key and retrieve it.
gotit = keys_->find("key2");
key = gotit->second;
// Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key2", "algo2", "secret2"));
+ EXPECT_TRUE(checkKey(key, "key2", TSIGKeyInfo::SHA1_STR, "secret2"));
// Find the 3rd key and retrieve it.
gotit = keys_->find("key3");
key = gotit->second;
// Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key3", "algo3", "secret3"));
+ EXPECT_TRUE(checkKey(key, "key3", TSIGKeyInfo::SHA256_STR, "secret3"));
+
+ // Find the 4th key and retrieve it.
+ gotit = keys_->find("key4");
+ ASSERT_TRUE(gotit != keys_->end());
+ key = gotit->second;
+
+ // Verify the key contents.
+ EXPECT_TRUE(checkKey(key, "key4", TSIGKeyInfo::SHA224_STR, "secret4"));
+
+ // Find the 5th key and retrieve it.
+ gotit = keys_->find("key5");
+ ASSERT_TRUE(gotit != keys_->end());
+ key = gotit->second;
+
+ // Verify the key contents.
+ EXPECT_TRUE(checkKey(key, "key5", TSIGKeyInfo::SHA384_STR, "secret5"));
+
+ // Find the 6th key and retrieve it.
+ gotit = keys_->find("key6");
+ ASSERT_TRUE(gotit != keys_->end());
+ key = gotit->second;
+
+ // Verify the key contents.
+ EXPECT_TRUE(checkKey(key, "key6", TSIGKeyInfo::SHA512_STR, "secret6"));
}
/// @brief Tests the enforcement of data validation when parsing DnsServerInfos.
ASSERT_TRUE(fromJSON(config));
// Add keys to key map so key validation passes.
- addKey("d2_key.tmark.org", "algo1", "secret1");
- addKey("d2_key.billcat.net", "algo2", "secret2");
+ addKey("d2_key.tmark.org", "MD5", "secret1");
+ addKey("d2_key.billcat.net", "MD5", "secret2");
// Create the list parser
isc::dhcp::ParserPtr list_parser;