Kea  1.9.9-git
nsec3hash.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <stdint.h>
10 
11 #include <cassert>
12 #include <cstring>
13 #include <cstdlib>
14 #include <string>
15 #include <vector>
16 
17 #include <boost/noncopyable.hpp>
18 #include <boost/scoped_ptr.hpp>
19 
20 #include <exceptions/exceptions.h>
21 
22 #include <util/buffer.h>
23 #include <util/encode/base32hex.h>
24 
25 #include <cryptolink/cryptolink.h>
26 #include <cryptolink/crypto_hash.h>
27 
28 #include <dns/name.h>
29 #include <dns/labelsequence.h>
30 #include <dns/nsec3hash.h>
31 #include <dns/rdataclass.h>
32 #include <dns/name_internal.h>
33 
34 using namespace std;
35 using namespace isc::util;
36 using namespace isc::util::encode;
37 using namespace isc::cryptolink;
38 using namespace isc::dns;
39 using namespace isc::dns::rdata;
40 
41 namespace {
42 
53 class NSEC3HashRFC5155 : boost::noncopyable, public NSEC3Hash {
54 private:
55  // This is the algorithm number for SHA1/NSEC3 as defined in RFC5155.
56  static const uint8_t NSEC3_HASH_SHA1 = 1;
57  // For digest_ allocation
58  static const size_t DEFAULT_DIGEST_LENGTH = 32;
59 
60 public:
61  NSEC3HashRFC5155(uint8_t algorithm, uint16_t iterations,
62  const uint8_t* salt_data, size_t salt_length) :
63  algorithm_(algorithm), iterations_(iterations),
64  salt_data_(NULL), salt_length_(salt_length),
65  digest_(DEFAULT_DIGEST_LENGTH), obuf_(Name::MAX_WIRE)
66  {
67  if (algorithm_ != NSEC3_HASH_SHA1) {
68  isc_throw(UnknownNSEC3HashAlgorithm, "Unknown NSEC3 algorithm: " <<
69  static_cast<unsigned int>(algorithm_));
70  }
71 
72  if (salt_length > 0) {
73  salt_data_ = static_cast<uint8_t*>(std::malloc(salt_length));
74  if (salt_data_ == NULL) {
75  throw std::bad_alloc();
76  }
77  std::memcpy(salt_data_, salt_data, salt_length);
78  }
79  }
80 
81  virtual ~NSEC3HashRFC5155() {
82  std::free(salt_data_);
83  }
84 
85  virtual std::string calculate(const Name& name) const;
86  virtual std::string calculate(const LabelSequence& ls) const;
87 
88  virtual bool match(const generic::NSEC3& nsec3) const;
89  virtual bool match(const generic::NSEC3PARAM& nsec3param) const;
90  bool match(uint8_t algorithm, uint16_t iterations,
91  const vector<uint8_t>& salt) const;
92 
93 private:
94  std::string calculateForWiredata(const uint8_t* data, size_t length) const;
95 
96  const uint8_t algorithm_;
97  const uint16_t iterations_;
98  uint8_t* salt_data_;
99  const size_t salt_length_;
100 
101  // The following members are placeholder of work place and don't hold
102  // any state over multiple calls so can be mutable without breaking
103  // constness.
104  mutable OutputBuffer digest_;
105  mutable vector<uint8_t> vdigest_;
106  mutable OutputBuffer obuf_;
107 };
108 
109 inline void
110 iterateSHA1(const uint8_t* input, size_t inlength,
111  const uint8_t* salt, size_t saltlen,
112  OutputBuffer& output)
113 {
114  boost::scoped_ptr<Hash> hash(CryptoLink::getCryptoLink().createHash(SHA1));
115  hash->update(input, inlength);
116  hash->update(salt, saltlen); // this works whether saltlen == or > 0
117  hash->final(output, hash->getOutputLength());
118 }
119 
120 string
121 NSEC3HashRFC5155::calculateForWiredata(const uint8_t* data,
122  size_t length) const
123 {
124  // We first need to normalize the name by converting all upper case
125  // characters in the labels to lower ones.
126 
127  uint8_t name_buf[256];
128  assert(length < sizeof (name_buf));
129 
130  const uint8_t *p1 = data;
131  uint8_t *p2 = name_buf;
132  while (*p1 != 0) {
133  char len = *p1;
134 
135  *p2++ = *p1++;
136  while (len--) {
138  }
139  }
140 
141  *p2 = *p1;
142 
143  digest_.clear();
144  iterateSHA1(name_buf, length,
145  salt_data_, salt_length_, digest_);
146  const uint8_t* dgst_data = static_cast<const uint8_t*>(digest_.getData());
147  size_t dgst_len = digest_.getLength();
148  for (unsigned int n = 0; n < iterations_; ++n) {
149  digest_.clear();
150  iterateSHA1(dgst_data, dgst_len, salt_data_, salt_length_, digest_);
151  }
152 
153  vdigest_.resize(dgst_len);
154  std::memcpy(&vdigest_[0], dgst_data, dgst_len);
155  return (encodeBase32Hex(vdigest_));
156 }
157 
158 string
159 NSEC3HashRFC5155::calculate(const Name& name) const {
160  obuf_.clear();
161  name.toWire(obuf_);
162 
163  return (calculateForWiredata(static_cast<const uint8_t*>(obuf_.getData()),
164  obuf_.getLength()));
165 }
166 
167 string
168 NSEC3HashRFC5155::calculate(const LabelSequence& ls) const {
169  assert(ls.isAbsolute());
170 
171  size_t length;
172  const uint8_t* data = ls.getData(&length);
173 
174  return (calculateForWiredata(data, length));
175 }
176 
177 bool
178 NSEC3HashRFC5155::match(uint8_t algorithm, uint16_t iterations,
179  const vector<uint8_t>& salt) const
180 {
181  return (algorithm_ == algorithm && iterations_ == iterations &&
182  salt_length_ == salt.size() &&
183  ((salt_length_ == 0) ||
184  memcmp(salt_data_, &salt[0], salt_length_) == 0));
185 }
186 
187 bool
188 NSEC3HashRFC5155::match(const generic::NSEC3& nsec3) const {
189  return (match(nsec3.getHashalg(), nsec3.getIterations(),
190  nsec3.getSalt()));
191 }
192 
193 bool
194 NSEC3HashRFC5155::match(const generic::NSEC3PARAM& nsec3param) const {
195  return (match(nsec3param.getHashalg(), nsec3param.getIterations(),
196  nsec3param.getSalt()));
197 }
198 
199 // A static pointer that refers to the currently usable creator.
200 // Only get/setNSEC3HashCreator are expected to get access to this variable
201 // directly.
202 const NSEC3HashCreator* creator;
203 
204 // The accessor to the current creator. If it's not explicitly set or has
205 // been reset from a customized one, the default creator will be used.
206 const NSEC3HashCreator*
207 getNSEC3HashCreator() {
208  static DefaultNSEC3HashCreator default_creator;
209  if (creator == NULL) {
210  creator = &default_creator;
211  }
212  return (creator);
213 }
214 
215 } // end of unnamed namespace
216 
217 namespace isc {
218 namespace dns {
219 
220 NSEC3Hash*
221 NSEC3Hash::create(const generic::NSEC3PARAM& param) {
222  return (getNSEC3HashCreator()->create(param));
223 }
224 
225 NSEC3Hash*
226 NSEC3Hash::create(const generic::NSEC3& nsec3) {
227  return (getNSEC3HashCreator()->create(nsec3));
228 }
229 
230 NSEC3Hash*
231 NSEC3Hash::create(uint8_t algorithm, uint16_t iterations,
232  const uint8_t* salt_data, size_t salt_length) {
233  return (getNSEC3HashCreator()->create(algorithm, iterations,
234  salt_data, salt_length));
235 }
236 
237 NSEC3Hash*
238 DefaultNSEC3HashCreator::create(const generic::NSEC3PARAM& param) const {
239  const vector<uint8_t>& salt = param.getSalt();
240  return (new NSEC3HashRFC5155(param.getHashalg(), param.getIterations(),
241  salt.empty() ? NULL : &salt[0],
242  salt.size()));
243 }
244 
245 NSEC3Hash*
246 DefaultNSEC3HashCreator::create(const generic::NSEC3& nsec3) const {
247  const vector<uint8_t>& salt = nsec3.getSalt();
248  return (new NSEC3HashRFC5155(nsec3.getHashalg(), nsec3.getIterations(),
249  salt.empty() ? NULL : &salt[0],
250  salt.size()));
251 }
252 
253 NSEC3Hash*
254 DefaultNSEC3HashCreator::create(uint8_t algorithm, uint16_t iterations,
255  const uint8_t* salt_data,
256  size_t salt_length) const
257 {
258  return (new NSEC3HashRFC5155(algorithm, iterations,
259  salt_data, salt_length));
260 }
261 
262 void
264  creator = new_creator;
265 }
266 
267 } // namespace dns
268 } // namespace isc
The Name class encapsulates DNS names.
Definition: name.h:223
void setNSEC3HashCreator(const NSEC3HashCreator *new_creator)
The registrar of NSEC3HashCreator.
Definition: nsec3hash.cc:263
A calculator of NSEC3 hashes.
Definition: nsec3hash.h:74
STL namespace.
uint16_t getIterations() const
An exception that is thrown for when an NSEC3Hash object is constructed with an unknown hash algorith...
Definition: nsec3hash.h:33
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: edns.h:19
uint8_t getHashalg() const
Specialized methods.
Factory class of NSEC3Hash.
Definition: nsec3hash.h:203
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
Defines the logger used by the top-level component of kea-dhcp-ddns.
const uint8_t * getData(size_t *len) const
Return the wire-format data for this LabelSequence.
bool isAbsolute() const
Checks whether the label sequence is absolute.
The default NSEC3Hash creator.
Definition: nsec3hash.h:258
std::string encodeBase32Hex(const std::vector< uint8_t > &binary)
Encode binary data in the base32hex format.
Definition: base_n.cc:459
void toWire(AbstractMessageRenderer &renderer) const
Render the Name in the wire format with compression.
Definition: name.cc:502
const std::vector< uint8_t > & getSalt() const
Light-weight Accessor to Name data.
Definition: labelsequence.h:35
const std::vector< uint8_t > & getSalt() const
const uint8_t maptolower[]
Definition: name.cc:73