From: Thomas Markwalder Date: Wed, 14 May 2014 19:45:34 +0000 (-0400) Subject: [3432] TSIGKeyInfo now creates and owns a dns::TSIGKey X-Git-Tag: trac3434_base~20^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3784b4690dfb753bfb60f238cb048a5257909851;p=thirdparty%2Fkea.git [3432] TSIGKeyInfo now creates and owns a dns::TSIGKey d2::TSIGKeyInfo now has an instance member for a dns::TSIGKey instance, which is created during the TSIGKeyInfo's construction. --- diff --git a/src/bin/d2/d2_config.cc b/src/bin/d2/d2_config.cc index fbfbf763d3..95032c6249 100644 --- a/src/bin/d2/d2_config.cc +++ b/src/bin/d2/d2_config.cc @@ -29,14 +29,56 @@ namespace d2 { // *********************** 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 ************************* @@ -212,9 +254,6 @@ TSIGKeyInfoParser::build(isc::data::ConstElementPtr key_config) { 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"); @@ -265,9 +304,6 @@ TSIGKeyInfoParser::createConfigParser(const std::string& config_id) { 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 ************************* diff --git a/src/bin/d2/d2_config.h b/src/bin/d2/d2_config.h index 5af60eee80..b996f018aa 100644 --- a/src/bin/d2/d2_config.h +++ b/src/bin/d2/d2_config.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -145,22 +146,39 @@ public: /// @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); @@ -174,7 +192,7 @@ public: 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 { @@ -188,18 +206,55 @@ public: 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. diff --git a/src/bin/d2/tests/d2_cfg_mgr_unittests.cc b/src/bin/d2/tests/d2_cfg_mgr_unittests.cc index e1b3313f1d..aa28f087df 100644 --- a/src/bin/d2/tests/d2_cfg_mgr_unittests.cc +++ b/src/bin/d2/tests/d2_cfg_mgr_unittests.cc @@ -145,6 +145,11 @@ bool checkKey(TSIGKeyInfoPtr key, const char* name, result = false; } + if (!key->getTSIGKey()) { + EXPECT_TRUE (key->getTSIGKey()); + return false; + } + return (result); } @@ -256,7 +261,7 @@ TEST_F(TSIGKeyInfoTest, invalidEntry) { // Config with a blank name entry. std::string config = "{" " \"name\": \"\" , " - " \"algorithm\": \"md5\" , " + " \"algorithm\": \"MD5\" , " " \"secret\": \"0123456789\" " "}"; ASSERT_TRUE(fromJSON(config)); @@ -276,10 +281,23 @@ TEST_F(TSIGKeyInfoTest, invalidEntry) { // 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\": \"\" " "}"; @@ -295,7 +313,7 @@ TEST_F(TSIGKeyInfoTest, validEntry) { // 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)); @@ -314,7 +332,7 @@ TEST_F(TSIGKeyInfoTest, validEntry) { 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 @@ -324,7 +342,7 @@ TEST_F(TSIGKeyInfoTest, invalidTSIGKeyList) { std::string config = "[" " { \"name\": \"key1\" , " - " \"algorithm\": \"algo1\" ," + " \"algorithm\": \"MD5\" ," " \"secret\": \"secret11\" " " }," " { \"name\": \"key2\" , " @@ -332,7 +350,7 @@ TEST_F(TSIGKeyInfoTest, invalidTSIGKeyList) { " \"secret\": \"secret12\" " " }," " { \"name\": \"key3\" , " - " \"algorithm\": \"algo3\" ," + " \"algorithm\": \"MD5\" ," " \"secret\": \"secret13\" " " }" " ]"; @@ -354,15 +372,15 @@ TEST_F(TSIGKeyInfoTest, duplicateTSIGKey) { 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\" " " }" " ]"; @@ -378,21 +396,34 @@ TEST_F(TSIGKeyInfoTest, duplicateTSIGKey) { } /// @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\" " " }" " ]"; @@ -407,7 +438,7 @@ TEST_F(TSIGKeyInfoTest, validTSIGKeyList) { // 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"); @@ -415,7 +446,7 @@ TEST_F(TSIGKeyInfoTest, validTSIGKeyList) { 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"); @@ -423,7 +454,7 @@ TEST_F(TSIGKeyInfoTest, validTSIGKeyList) { 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"); @@ -431,7 +462,31 @@ TEST_F(TSIGKeyInfoTest, validTSIGKeyList) { 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. @@ -743,8 +798,8 @@ TEST_F(DdnsDomainTest, DdnsDomainListParsing) { 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;