Branch data Line data Source code
1 : : // Copyright (C) 2010 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 <map>
16 : : #include <utility>
17 : : #include <vector>
18 : : #include <sstream>
19 : :
20 : : #include <exceptions/exceptions.h>
21 : :
22 : : #include <cryptolink/cryptolink.h>
23 : :
24 : : #include <dns/name.h>
25 : : #include <util/encode/base64.h>
26 : : #include <dns/tsigkey.h>
27 : :
28 : : using namespace std;
29 : : using namespace isc::cryptolink;
30 : :
31 : : namespace isc {
32 : : namespace dns {
33 : : namespace {
34 : : HashAlgorithm
35 : 302 : convertAlgorithmName(const isc::dns::Name& name) {
36 [ + + ]: 604 : if (name == TSIGKey::HMACMD5_NAME()) {
37 : : return (isc::cryptolink::MD5);
38 : : }
39 [ + + ]: 166 : if (name == TSIGKey::HMACSHA1_NAME()) {
40 : : return (isc::cryptolink::SHA1);
41 : : }
42 [ + + ]: 80 : if (name == TSIGKey::HMACSHA256_NAME()) {
43 : : return (isc::cryptolink::SHA256);
44 : : }
45 [ + + ]: 34 : if (name == TSIGKey::HMACSHA224_NAME()) {
46 : : return (isc::cryptolink::SHA224);
47 : : }
48 [ + + ]: 28 : if (name == TSIGKey::HMACSHA384_NAME()) {
49 : : return (isc::cryptolink::SHA384);
50 : : }
51 [ + + ]: 24 : if (name == TSIGKey::HMACSHA512_NAME()) {
52 : : return (isc::cryptolink::SHA512);
53 : : }
54 : :
55 : 302 : return (isc::cryptolink::UNKNOWN_HASH);
56 : : }
57 : : }
58 : :
59 : : struct
60 [ + - ][ + - ]: 1267 : TSIGKey::TSIGKeyImpl {
61 : 291 : TSIGKeyImpl(const Name& key_name, const Name& algorithm_name,
62 : : isc::cryptolink::HashAlgorithm algorithm,
63 : : const void* secret, size_t secret_len) :
64 : : key_name_(key_name), algorithm_name_(algorithm_name),
65 : : algorithm_(algorithm),
66 : : secret_(static_cast<const uint8_t*>(secret),
67 [ + - ][ + - ]: 291 : static_cast<const uint8_t*>(secret) + secret_len)
68 : : {
69 : : // Convert the key and algorithm names to the canonical form.
70 [ + - ]: 291 : key_name_.downcase();
71 [ + - ]: 291 : algorithm_name_.downcase();
72 : 291 : }
73 : : Name key_name_;
74 : : Name algorithm_name_;
75 : : const isc::cryptolink::HashAlgorithm algorithm_;
76 : : const vector<uint8_t> secret_;
77 : : };
78 : :
79 : 168 : TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
80 : 168 : const void* secret, size_t secret_len) : impl_(NULL)
81 : : {
82 : 168 : const HashAlgorithm algorithm = convertAlgorithmName(algorithm_name);
83 [ + + ][ + + ]: 168 : if ((secret != NULL && secret_len == 0) ||
84 : : (secret == NULL && secret_len != 0)) {
85 [ + - ][ + - ]: 4 : isc_throw(InvalidParameter,
[ + - ][ + - ]
[ + - ]
86 : : "TSIGKey secret and its length are inconsistent: " <<
87 : : key_name << ":" << algorithm_name);
88 : : }
89 [ + + ]: 166 : if (algorithm == isc::cryptolink::UNKNOWN_HASH && secret_len != 0) {
90 [ + - ][ + - ]: 4 : isc_throw(InvalidParameter,
[ + - ][ + - ]
[ + - ]
91 : : "TSIGKey with unknown algorithm has non empty secret: " <<
92 : : key_name << ":" << algorithm_name);
93 : : }
94 : : impl_ = new TSIGKeyImpl(key_name, algorithm_name, algorithm, secret,
95 [ + - ]: 164 : secret_len);
96 : 164 : }
97 : :
98 : 147 : TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) {
99 : : try {
100 [ + - + - ]: 294 : istringstream iss(str);
101 : :
102 : 147 : string keyname_str;
103 [ + - ]: 147 : getline(iss, keyname_str, ':');
104 [ + + ][ + - ]: 147 : if (iss.fail() || iss.bad() || iss.eof()) {
[ + + ][ + + ]
105 [ + - ][ + - ]: 6 : isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
[ + - ][ + - ]
106 : : }
107 : :
108 : 144 : string secret_str;
109 [ + - ]: 144 : getline(iss, secret_str, ':');
110 [ + + ][ + - ]: 144 : if (iss.fail() || iss.bad()) {
[ + + ]
111 [ + - ][ + - ]: 6 : isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
[ + - ][ + - ]
112 : : }
113 : :
114 : 141 : string algo_str;
115 [ + + ]: 141 : if (!iss.eof()) {
116 [ + - ]: 40 : getline(iss, algo_str);
117 : : }
118 [ + + ][ + - ]: 141 : if (iss.fail() || iss.bad()) {
[ + + ]
119 [ + - ][ + - ]: 14 : isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
[ + - ][ + - ]
120 : : }
121 : :
122 : : const Name algo_name(algo_str.empty() ? "hmac-md5.sig-alg.reg.int" :
123 [ + + ][ + - ]: 268 : algo_str);
[ + - ][ + - ]
124 [ + - ]: 134 : const HashAlgorithm algorithm = convertAlgorithmName(algo_name);
125 : :
126 : 134 : vector<uint8_t> secret;
127 [ + + ]: 134 : isc::util::encode::decodeBase64(secret_str, secret);
128 : :
129 [ + + ][ + + ]: 131 : if (algorithm == isc::cryptolink::UNKNOWN_HASH && !secret.empty()) {
[ + + ]
130 [ + - ][ + - ]: 6 : isc_throw(InvalidParameter,
[ + - ][ + - ]
131 : : "TSIG key with unknown algorithm has non empty secret: "
132 : : << str);
133 : : }
134 : :
135 : 127 : impl_ = new TSIGKeyImpl(Name(keyname_str), algo_name, algorithm,
136 : 126 : secret.empty() ? NULL : &secret[0],
137 [ + + ][ + + ]: 254 : secret.size());
[ + - ][ + - ]
138 [ - + ]: 40 : } catch (const Exception& e) {
139 : : // 'reduce' the several types of exceptions name parsing and
140 : : // Base64 decoding can throw to just the InvalidParameter
141 [ - + ][ - + ]: 40 : isc_throw(InvalidParameter, e.what());
[ - + ]
142 : : }
143 : 127 : }
144 : :
145 : :
146 [ + - ]: 487 : TSIGKey::TSIGKey(const TSIGKey& source) : impl_(new TSIGKeyImpl(*source.impl_))
147 : 487 : {}
148 : :
149 : : TSIGKey&
150 : 2 : TSIGKey::operator=(const TSIGKey& source) {
151 [ + + ]: 2 : if (impl_ == source.impl_) {
152 : : return (*this);
153 : : }
154 : :
155 [ + - ]: 1 : TSIGKeyImpl* newimpl = new TSIGKeyImpl(*source.impl_);
156 [ + - ]: 2 : delete impl_;
157 : 1 : impl_ = newimpl;
158 : :
159 : 2 : return (*this);
160 : : }
161 : :
162 : 778 : TSIGKey::~TSIGKey() {
163 [ + - ]: 1556 : delete impl_;
164 : 778 : }
165 : :
166 : : const Name&
167 : 861 : TSIGKey::getKeyName() const {
168 : 861 : return (impl_->key_name_);
169 : : }
170 : :
171 : : const Name&
172 : 834 : TSIGKey::getAlgorithmName() const {
173 : 834 : return (impl_->algorithm_name_);
174 : : }
175 : :
176 : : isc::cryptolink::HashAlgorithm
177 : 431 : TSIGKey::getAlgorithm() const {
178 : 431 : return (impl_->algorithm_);
179 : : }
180 : :
181 : : const void*
182 : 490 : TSIGKey::getSecret() const {
183 [ + + ]: 976 : return ((impl_->secret_.size() > 0) ? &impl_->secret_[0] : NULL);
184 : : }
185 : :
186 : : size_t
187 : 465 : TSIGKey::getSecretLength() const {
188 : 465 : return (impl_->secret_.size());
189 : : }
190 : :
191 : : std::string
192 : 25 : TSIGKey::toText() const {
193 : 25 : const vector<uint8_t> secret_v(static_cast<const uint8_t*>(getSecret()),
194 : 25 : static_cast<const uint8_t*>(getSecret()) +
195 : 75 : getSecretLength());
196 [ + - ]: 50 : std::string secret_str = isc::util::encode::encodeBase64(secret_v);
197 : :
198 [ + - ]: 50 : return (getKeyName().toText() + ":" + secret_str + ":" +
199 [ + - ][ + - ]: 100 : getAlgorithmName().toText());
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
200 : : }
201 : :
202 : : const
203 : 456 : Name& TSIGKey::HMACMD5_NAME() {
204 [ + + ][ + - ]: 456 : static Name alg_name("hmac-md5.sig-alg.reg.int");
[ + - ][ + - ]
205 : 456 : return (alg_name);
206 : : }
207 : :
208 : : const
209 : 130 : Name& TSIGKey::HMACSHA1_NAME() {
210 [ + + ][ + - ]: 130 : static Name alg_name("hmac-sha1");
[ + - ][ + - ]
211 : 130 : return (alg_name);
212 : : }
213 : :
214 : : const
215 : 85 : Name& TSIGKey::HMACSHA256_NAME() {
216 [ + + ][ + - ]: 85 : static Name alg_name("hmac-sha256");
[ + - ][ + - ]
217 : 85 : return (alg_name);
218 : : }
219 : :
220 : : const
221 : 51 : Name& TSIGKey::HMACSHA224_NAME() {
222 [ + + ][ + - ]: 51 : static Name alg_name("hmac-sha224");
[ + - ][ + - ]
223 : 51 : return (alg_name);
224 : : }
225 : :
226 : : const
227 : 46 : Name& TSIGKey::HMACSHA384_NAME() {
228 [ + + ][ + - ]: 46 : static Name alg_name("hmac-sha384");
[ + - ][ + - ]
229 : 46 : return (alg_name);
230 : : }
231 : :
232 : : const
233 : 44 : Name& TSIGKey::HMACSHA512_NAME() {
234 [ + + ][ + - ]: 44 : static Name alg_name("hmac-sha512");
[ + - ][ + - ]
235 : 44 : return (alg_name);
236 : : }
237 : :
238 : 292 : struct TSIGKeyRing::TSIGKeyRingImpl {
239 : : typedef map<Name, TSIGKey> TSIGKeyMap;
240 : : typedef pair<Name, TSIGKey> NameAndKey;
241 : : TSIGKeyMap keys;
242 : : };
243 : :
244 : 146 : TSIGKeyRing::TSIGKeyRing() : impl_(new TSIGKeyRingImpl) {
245 : 146 : }
246 : :
247 : 146 : TSIGKeyRing::~TSIGKeyRing() {
248 [ + - ]: 292 : delete impl_;
249 : 146 : }
250 : :
251 : : unsigned int
252 : 19 : TSIGKeyRing::size() const {
253 : 19 : return (impl_->keys.size());
254 : : }
255 : :
256 : : TSIGKeyRing::Result
257 : 59 : TSIGKeyRing::add(const TSIGKey& key) {
258 [ + + ]: 59 : if (impl_->keys.insert(
259 [ + - ]: 118 : TSIGKeyRingImpl::NameAndKey(key.getKeyName(), key)).second
260 : : == true) {
261 : : return (SUCCESS);
262 : : } else {
263 : 59 : return (EXIST);
264 : : }
265 : : }
266 : :
267 : : TSIGKeyRing::Result
268 : 8 : TSIGKeyRing::remove(const Name& key_name) {
269 [ + + ]: 8 : return (impl_->keys.erase(key_name) == 1 ? SUCCESS : NOTFOUND);
270 : : }
271 : :
272 : : TSIGKeyRing::FindResult
273 : 67 : TSIGKeyRing::find(const Name& key_name, const Name& algorithm_name) const {
274 : : TSIGKeyRingImpl::TSIGKeyMap::const_iterator found =
275 : 134 : impl_->keys.find(key_name);
276 [ + + + + ]: 110 : if (found == impl_->keys.end() ||
[ + + ]
277 : 43 : (*found).second.getAlgorithmName() != algorithm_name) {
278 : 33 : return (FindResult(NOTFOUND, NULL));
279 : : }
280 : 67 : return (FindResult(SUCCESS, &((*found).second)));
281 : : }
282 : :
283 : : } // namespace dns
284 : 513 : } // namespace isc
|