Branch data Line data Source code
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 : :
15 : : #include <stdint.h>
16 : :
17 : : #include <cassert>
18 : : #include <cstring>
19 : : #include <string>
20 : : #include <vector>
21 : :
22 : : #include <boost/noncopyable.hpp>
23 : :
24 : : #include <exceptions/exceptions.h>
25 : :
26 : : #include <util/buffer.h>
27 : : #include <util/encode/base32hex.h>
28 : : #include <util/hash/sha1.h>
29 : :
30 : : #include <dns/name.h>
31 : : #include <dns/nsec3hash.h>
32 : : #include <dns/rdataclass.h>
33 : :
34 : : using namespace std;
35 : : using namespace isc::util;
36 : : using namespace isc::util::encode;
37 : : using namespace isc::util::hash;
38 : : using namespace isc::dns;
39 : : using namespace isc::dns::rdata;
40 : :
41 : : namespace {
42 : :
43 : : /// \brief A derived class of \c NSEC3Hash that implements the standard hash
44 : : /// calculation specified in RFC5155.
45 : : ///
46 : : /// Currently the only pre-defined algorithm in the RFC is SHA1. So we don't
47 : : /// over-generalize it at the moment, and rather hardocde it and assume that
48 : : /// specific algorithm.
49 : : ///
50 : : /// The implementation details are only open within this file, but to avoid
51 : : /// an accidental error in this implementation we explicitly make it non
52 : : /// copyable.
53 : 168 : 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 : :
58 : : public:
59 : 60 : NSEC3HashRFC5155(uint8_t algorithm, uint16_t iterations,
60 : : const vector<uint8_t>& salt) :
61 : : algorithm_(algorithm), iterations_(iterations),
62 [ + - ]: 64 : salt_(salt), digest_(SHA1_HASHSIZE), obuf_(Name::MAX_WIRE)
63 : : {
64 [ + + ]: 60 : if (algorithm_ != NSEC3_HASH_SHA1) {
65 [ + - ][ + - ]: 12 : isc_throw(UnknownNSEC3HashAlgorithm, "Unknown NSEC3 algorithm: " <<
66 : : static_cast<unsigned int>(algorithm_));
67 : : }
68 [ + - ]: 56 : SHA1Reset(&sha1_ctx_);
69 : 56 : }
70 : :
71 : : virtual std::string calculate(const Name& name) const;
72 : :
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 : :
78 : : private:
79 : : const uint8_t algorithm_;
80 : : const uint16_t iterations_;
81 : : const vector<uint8_t> salt_;
82 : :
83 : : // The following members are placeholder of work place and don't hold
84 : : // any state over multiple calls so can be mutable without breaking
85 : : // constness.
86 : : mutable SHA1Context sha1_ctx_;
87 : : mutable vector<uint8_t> digest_;
88 : : mutable OutputBuffer obuf_;
89 : : };
90 : :
91 : : inline void
92 : : iterateSHA1(SHA1Context* ctx, const uint8_t* input, size_t inlength,
93 : : const uint8_t* salt, size_t saltlen,
94 : : uint8_t output[SHA1_HASHSIZE])
95 : : {
96 [ + - ][ + - ]: 802 : SHA1Reset(ctx);
97 [ + - ][ + - ]: 802 : SHA1Input(ctx, input, inlength);
98 [ + - ][ + - ]: 802 : SHA1Input(ctx, salt, saltlen); // this works whether saltlen == or > 0
99 [ + - ][ + - ]: 802 : SHA1Result(ctx, output);
100 : : }
101 : :
102 : : string
103 : 26 : NSEC3HashRFC5155::calculate(const Name& name) const {
104 : : // We first need to normalize the name by converting all upper case
105 : : // characters in the labels to lower ones.
106 : : obuf_.clear();
107 : : Name name_copy(name);
108 [ + - ]: 26 : name_copy.downcase();
109 [ + - ]: 26 : name_copy.toWire(obuf_);
110 : :
111 : 26 : const uint8_t saltlen = salt_.size();
112 [ + + ]: 26 : const uint8_t* const salt = (saltlen > 0) ? &salt_[0] : NULL;
113 : 26 : uint8_t* const digest = &digest_[0];
114 [ - + ]: 26 : assert(digest_.size() == SHA1_HASHSIZE);
115 : :
116 : : iterateSHA1(&sha1_ctx_, static_cast<const uint8_t*>(obuf_.getData()),
117 : 52 : obuf_.getLength(), salt, saltlen, digest);
118 [ + + ]: 802 : for (unsigned int n = 0; n < iterations_; ++n) {
119 : 776 : iterateSHA1(&sha1_ctx_, digest, SHA1_HASHSIZE, salt, saltlen, digest);
120 : : }
121 : :
122 [ + - ]: 52 : return (encodeBase32Hex(digest_));
123 : : }
124 : :
125 : : bool
126 : 225 : NSEC3HashRFC5155::match(uint8_t algorithm, uint16_t iterations,
127 : : const vector<uint8_t>& salt) const
128 : : {
129 : : return (algorithm_ == algorithm && iterations_ == iterations &&
130 : : salt_.size() == salt.size() &&
131 [ + + ][ + + ]: 225 : (salt_.empty() || memcmp(&salt_[0], &salt[0], salt_.size()) == 0));
[ + + ][ + - ]
[ + + ]
132 : : }
133 : :
134 : : bool
135 : 200 : NSEC3HashRFC5155::match(const generic::NSEC3& nsec3) const {
136 : 200 : return (match(nsec3.getHashalg(), nsec3.getIterations(),
137 : 400 : nsec3.getSalt()));
138 : : }
139 : :
140 : : bool
141 : 25 : NSEC3HashRFC5155::match(const generic::NSEC3PARAM& nsec3param) const {
142 : 25 : return (match(nsec3param.getHashalg(), nsec3param.getIterations(),
143 : 50 : nsec3param.getSalt()));
144 : : }
145 : :
146 : : // A static pointer that refers to the currently usable creator.
147 : : // Only get/setNSEC3HashCreator are expected to get access to this variable
148 : : // directly.
149 : : const NSEC3HashCreator* creator;
150 : :
151 : : // The accessor to the current creator. If it's not explicitly set or has
152 : : // been reset from a customized one, the default creator will be used.
153 : : const NSEC3HashCreator*
154 : 75 : getNSEC3HashCreator() {
155 [ + + ][ + - ]: 75 : static DefaultNSEC3HashCreator default_creator;
156 [ + + ]: 75 : if (creator == NULL) {
157 : 23 : creator = &default_creator;
158 : : }
159 : 75 : return (creator);
160 : : }
161 : :
162 : : } // end of unnamed namespace
163 : :
164 : : namespace isc {
165 : : namespace dns {
166 : :
167 : : NSEC3Hash*
168 : 46 : NSEC3Hash::create(const generic::NSEC3PARAM& param) {
169 : 46 : return (getNSEC3HashCreator()->create(param));
170 : : }
171 : :
172 : : NSEC3Hash*
173 : 29 : NSEC3Hash::create(const generic::NSEC3& nsec3) {
174 : 29 : return (getNSEC3HashCreator()->create(nsec3));
175 : : }
176 : :
177 : : NSEC3Hash*
178 : 37 : DefaultNSEC3HashCreator::create(const generic::NSEC3PARAM& param) const {
179 : 37 : return (new NSEC3HashRFC5155(param.getHashalg(), param.getIterations(),
180 [ + + ]: 37 : param.getSalt()));
181 : : }
182 : :
183 : : NSEC3Hash*
184 : 23 : DefaultNSEC3HashCreator::create(const generic::NSEC3& nsec3) const {
185 : 23 : return (new NSEC3HashRFC5155(nsec3.getHashalg(), nsec3.getIterations(),
186 [ + + ]: 23 : nsec3.getSalt()));
187 : : }
188 : :
189 : : void
190 : 227 : setNSEC3HashCreator(const NSEC3HashCreator* new_creator) {
191 : 227 : creator = new_creator;
192 : 227 : }
193 : :
194 : : } // namespace dns
195 : 161 : } // namespace isc
|