Parcourir la source

[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.
Thomas Markwalder il y a 11 ans
Parent
commit
3784b4690d
3 fichiers modifiés avec 181 ajouts et 35 suppressions
  1. 43 7
      src/bin/d2/d2_config.cc
  2. 65 10
      src/bin/d2/d2_config.h
  3. 73 18
      src/bin/d2/tests/d2_cfg_mgr_unittests.cc

+ 43 - 7
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  *************************

+ 65 - 10
src/bin/d2/d2_config.h

@@ -19,6 +19,7 @@
 #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>
@@ -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.

+ 73 - 18
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;