nsec3hash.cc 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <stdint.h>
  15. #include <cassert>
  16. #include <cstring>
  17. #include <cstdlib>
  18. #include <string>
  19. #include <vector>
  20. #include <boost/noncopyable.hpp>
  21. #include <exceptions/exceptions.h>
  22. #include <util/buffer.h>
  23. #include <util/encode/base32hex.h>
  24. #include <util/hash/sha1.h>
  25. #include <dns/name.h>
  26. #include <dns/nsec3hash.h>
  27. #include <dns/rdataclass.h>
  28. using namespace std;
  29. using namespace isc::util;
  30. using namespace isc::util::encode;
  31. using namespace isc::util::hash;
  32. using namespace isc::dns;
  33. using namespace isc::dns::rdata;
  34. namespace {
  35. /// \brief A derived class of \c NSEC3Hash that implements the standard hash
  36. /// calculation specified in RFC5155.
  37. ///
  38. /// Currently the only pre-defined algorithm in the RFC is SHA1. So we don't
  39. /// over-generalize it at the moment, and rather hardocde it and assume that
  40. /// specific algorithm.
  41. ///
  42. /// The implementation details are only open within this file, but to avoid
  43. /// an accidental error in this implementation we explicitly make it non
  44. /// copyable.
  45. class NSEC3HashRFC5155 : boost::noncopyable, public NSEC3Hash {
  46. private:
  47. // This is the algorithm number for SHA1/NSEC3 as defined in RFC5155.
  48. static const uint8_t NSEC3_HASH_SHA1 = 1;
  49. public:
  50. NSEC3HashRFC5155(uint8_t algorithm, uint16_t iterations,
  51. const uint8_t* salt_data, size_t salt_length) :
  52. algorithm_(algorithm), iterations_(iterations),
  53. salt_data_(NULL), salt_length_(salt_length),
  54. digest_(SHA1_HASHSIZE), obuf_(Name::MAX_WIRE)
  55. {
  56. if (algorithm_ != NSEC3_HASH_SHA1) {
  57. isc_throw(UnknownNSEC3HashAlgorithm, "Unknown NSEC3 algorithm: " <<
  58. static_cast<unsigned int>(algorithm_));
  59. }
  60. if (salt_length > 0) {
  61. salt_data_ = static_cast<uint8_t*>(std::malloc(salt_length));
  62. if (salt_data_ == NULL) {
  63. throw std::bad_alloc();
  64. }
  65. std::memcpy(salt_data_, salt_data, salt_length);
  66. }
  67. SHA1Reset(&sha1_ctx_);
  68. }
  69. virtual ~NSEC3HashRFC5155() {
  70. std::free(salt_data_);
  71. }
  72. virtual std::string calculate(const Name& name) const;
  73. virtual bool match(const generic::NSEC3& nsec3) const;
  74. virtual bool match(const generic::NSEC3PARAM& nsec3param) const;
  75. bool match(uint8_t algorithm, uint16_t iterations,
  76. const vector<uint8_t>& salt) const;
  77. private:
  78. const uint8_t algorithm_;
  79. const uint16_t iterations_;
  80. uint8_t* salt_data_;
  81. const size_t salt_length_;
  82. // The following members are placeholder of work place and don't hold
  83. // any state over multiple calls so can be mutable without breaking
  84. // constness.
  85. mutable SHA1Context sha1_ctx_;
  86. mutable vector<uint8_t> digest_;
  87. mutable OutputBuffer obuf_;
  88. };
  89. inline void
  90. iterateSHA1(SHA1Context* ctx, const uint8_t* input, size_t inlength,
  91. const uint8_t* salt, size_t saltlen,
  92. uint8_t output[SHA1_HASHSIZE])
  93. {
  94. SHA1Reset(ctx);
  95. SHA1Input(ctx, input, inlength);
  96. SHA1Input(ctx, salt, saltlen); // this works whether saltlen == or > 0
  97. SHA1Result(ctx, output);
  98. }
  99. string
  100. NSEC3HashRFC5155::calculate(const Name& name) const {
  101. // We first need to normalize the name by converting all upper case
  102. // characters in the labels to lower ones.
  103. obuf_.clear();
  104. Name name_copy(name);
  105. name_copy.downcase();
  106. name_copy.toWire(obuf_);
  107. uint8_t* const digest = &digest_[0];
  108. assert(digest_.size() == SHA1_HASHSIZE);
  109. iterateSHA1(&sha1_ctx_, static_cast<const uint8_t*>(obuf_.getData()),
  110. obuf_.getLength(), salt_data_, salt_length_, digest);
  111. for (unsigned int n = 0; n < iterations_; ++n) {
  112. iterateSHA1(&sha1_ctx_, digest, SHA1_HASHSIZE,
  113. salt_data_, salt_length_, digest);
  114. }
  115. return (encodeBase32Hex(digest_));
  116. }
  117. bool
  118. NSEC3HashRFC5155::match(uint8_t algorithm, uint16_t iterations,
  119. const vector<uint8_t>& salt) const
  120. {
  121. return (algorithm_ == algorithm && iterations_ == iterations &&
  122. salt_length_ == salt.size() &&
  123. ((salt_length_ == 0) ||
  124. memcmp(salt_data_, &salt[0], salt_length_) == 0));
  125. }
  126. bool
  127. NSEC3HashRFC5155::match(const generic::NSEC3& nsec3) const {
  128. return (match(nsec3.getHashalg(), nsec3.getIterations(),
  129. nsec3.getSalt()));
  130. }
  131. bool
  132. NSEC3HashRFC5155::match(const generic::NSEC3PARAM& nsec3param) const {
  133. return (match(nsec3param.getHashalg(), nsec3param.getIterations(),
  134. nsec3param.getSalt()));
  135. }
  136. // A static pointer that refers to the currently usable creator.
  137. // Only get/setNSEC3HashCreator are expected to get access to this variable
  138. // directly.
  139. const NSEC3HashCreator* creator;
  140. // The accessor to the current creator. If it's not explicitly set or has
  141. // been reset from a customized one, the default creator will be used.
  142. const NSEC3HashCreator*
  143. getNSEC3HashCreator() {
  144. static DefaultNSEC3HashCreator default_creator;
  145. if (creator == NULL) {
  146. creator = &default_creator;
  147. }
  148. return (creator);
  149. }
  150. } // end of unnamed namespace
  151. namespace isc {
  152. namespace dns {
  153. NSEC3Hash*
  154. NSEC3Hash::create(const generic::NSEC3PARAM& param) {
  155. return (getNSEC3HashCreator()->create(param));
  156. }
  157. NSEC3Hash*
  158. NSEC3Hash::create(const generic::NSEC3& nsec3) {
  159. return (getNSEC3HashCreator()->create(nsec3));
  160. }
  161. NSEC3Hash*
  162. NSEC3Hash::create(uint8_t algorithm, uint16_t iterations,
  163. const uint8_t* salt_data, size_t salt_length) {
  164. return (getNSEC3HashCreator()->create(algorithm, iterations,
  165. salt_data, salt_length));
  166. }
  167. NSEC3Hash*
  168. DefaultNSEC3HashCreator::create(const generic::NSEC3PARAM& param) const {
  169. const vector<uint8_t>& salt = param.getSalt();
  170. return (new NSEC3HashRFC5155(param.getHashalg(), param.getIterations(),
  171. salt.empty() ? NULL : &salt[0],
  172. salt.size()));
  173. }
  174. NSEC3Hash*
  175. DefaultNSEC3HashCreator::create(const generic::NSEC3& nsec3) const {
  176. const vector<uint8_t>& salt = nsec3.getSalt();
  177. return (new NSEC3HashRFC5155(nsec3.getHashalg(), nsec3.getIterations(),
  178. salt.empty() ? NULL : &salt[0],
  179. salt.size()));
  180. }
  181. NSEC3Hash*
  182. DefaultNSEC3HashCreator::create(uint8_t algorithm, uint16_t iterations,
  183. const uint8_t* salt_data,
  184. size_t salt_length) const
  185. {
  186. return (new NSEC3HashRFC5155(algorithm, iterations,
  187. salt_data, salt_length));
  188. }
  189. void
  190. setNSEC3HashCreator(const NSEC3HashCreator* new_creator) {
  191. creator = new_creator;
  192. }
  193. } // namespace dns
  194. } // namespace isc