Branch data Line data Source code
1 : : // Copyright (C) 2011 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 <sys/time.h>
16 : :
17 : : #include <stdint.h>
18 : :
19 : : #include <cassert>
20 : : #include <vector>
21 : :
22 : : #include <boost/shared_ptr.hpp>
23 : :
24 : : #include <exceptions/exceptions.h>
25 : :
26 : : #include <util/buffer.h>
27 : : #include <util/time_utilities.h>
28 : :
29 : : #include <dns/rdataclass.h>
30 : : #include <dns/rrclass.h>
31 : : #include <dns/tsig.h>
32 : : #include <dns/tsigerror.h>
33 : : #include <dns/tsigkey.h>
34 : :
35 : : #include <cryptolink/cryptolink.h>
36 : : #include <cryptolink/crypto_hmac.h>
37 : :
38 : : using namespace std;
39 : : using namespace isc::util;
40 : : using namespace isc::cryptolink;
41 : : using namespace isc::dns::rdata;
42 : :
43 : : namespace isc {
44 : : namespace dns {
45 : : namespace {
46 : : typedef boost::shared_ptr<HMAC> HMACPtr;
47 : :
48 : : // TSIG uses 48-bit unsigned integer to represent time signed.
49 : : // Since gettimeWrapper() returns a 64-bit *signed* integer, we
50 : : // make sure it's stored in an unsigned 64-bit integer variable and
51 : : // represents a value in the expected range. (In reality, however,
52 : : // gettimeWrapper() will return a positive integer that will fit
53 : : // in 48 bits)
54 : : uint64_t
55 : : getTSIGTime() {
56 : 276 : return (detail::gettimeWrapper() & 0x0000ffffffffffffULL);
57 : : }
58 : : }
59 : :
60 : 303 : struct TSIGContext::TSIGContextImpl {
61 : 303 : TSIGContextImpl(const TSIGKey& key,
62 : 287 : TSIGError error = TSIGError::NOERROR()) :
63 : : state_(INIT), key_(key), error_(error),
64 : 303 : previous_timesigned_(0), digest_len_(0)
65 : : {
66 [ + - ][ + + ]: 303 : if (error == TSIGError::NOERROR()) {
67 : : // In normal (NOERROR) case, the key should be valid, and we
68 : : // should be able to pre-create a corresponding HMAC object,
69 : : // which will be likely to be used for sign or verify later.
70 : : // We do this in the constructor so that we can know the expected
71 : : // digest length in advance. The creation should normally succeed,
72 : : // but the key information could be still broken, which could
73 : : // trigger an exception inside the cryptolink module. We ignore
74 : : // it at this moment; a subsequent sign/verify operation will try
75 : : // to create the HMAC, which would also fail.
76 : : try {
77 [ + - ]: 287 : hmac_.reset(CryptoLink::getCryptoLink().createHMAC(
78 : : key_.getSecret(), key_.getSecretLength(),
79 : : key_.getAlgorithm()),
80 [ + - ][ + - ]: 574 : deleteHMAC);
[ + - ][ + + ]
81 : 2 : } catch (const Exception&) {
82 [ - + ]: 305 : return;
83 : : }
84 [ + - ]: 285 : digest_len_ = hmac_->getOutputLength();
85 : : }
86 : : }
87 : :
88 : : // This helper method is used from verify(). It's expected to be called
89 : : // just before verify() returns. It updates internal state based on
90 : : // the verification result and return the TSIGError to be returned to
91 : : // the caller of verify(), so that verify() can call this method within
92 : : // its 'return' statement.
93 : 107 : TSIGError postVerifyUpdate(TSIGError error, const void* digest,
94 : : uint16_t digest_len)
95 : : {
96 [ + + ]: 107 : if (state_ == INIT) {
97 : 57 : state_ = RECEIVED_REQUEST;
98 [ + + ][ + + ]: 50 : } else if (state_ == SENT_REQUEST && error == TSIGError::NOERROR()) {
[ + + ]
99 : 12 : state_ = VERIFIED_RESPONSE;
100 : : }
101 [ + + ]: 107 : if (digest != NULL) {
102 : : previous_digest_.assign(static_cast<const uint8_t*>(digest),
103 : : static_cast<const uint8_t*>(digest) +
104 : 54 : digest_len);
105 : : }
106 : 107 : error_ = error;
107 : 107 : return (error);
108 : : }
109 : :
110 : : // A shortcut method to create an HMAC object for sign/verify. If one
111 : : // has been successfully created in the constructor, return it; otherwise
112 : : // create a new one and return it. In the former case, the ownership is
113 : : // transferred to the caller; the stored HMAC will be reset after the
114 : : // call.
115 : 252 : HMACPtr createHMAC() {
116 [ + + ]: 252 : if (hmac_) {
117 : : HMACPtr ret = HMACPtr();
118 : 114 : ret.swap(hmac_);
119 : : return (ret);
120 : : }
121 : 138 : return (HMACPtr(CryptoLink::getCryptoLink().createHMAC(
122 : : key_.getSecret(), key_.getSecretLength(),
123 : : key_.getAlgorithm()),
124 : 390 : deleteHMAC));
125 : : }
126 : :
127 : : // The following three are helper methods to compute the digest for
128 : : // TSIG sign/verify in order to unify the common code logic for sign()
129 : : // and verify() and to keep these callers concise.
130 : : // These methods take an HMAC object, which will be updated with the
131 : : // calculated digest.
132 : : // Note: All methods construct a local OutputBuffer as a work space with a
133 : : // fixed initial buffer size to avoid intermediate buffer extension.
134 : : // This should be efficient enough, especially for fundamentally expensive
135 : : // operation like cryptographic sign/verify, but if the creation of the
136 : : // buffer in each helper method is still identified to be a severe
137 : : // performance bottleneck, we could have this class a buffer as a member
138 : : // variable and reuse it throughout the object's lifetime. Right now,
139 : : // we prefer keeping the scope for local things as small as possible.
140 : : void digestPreviousMAC(HMACPtr hmac) const;
141 : : void digestTSIGVariables(HMACPtr hmac, uint16_t rrclass, uint32_t rrttl,
142 : : uint64_t time_signed, uint16_t fudge,
143 : : uint16_t error, uint16_t otherlen,
144 : : const void* otherdata,
145 : : bool time_variables_only) const;
146 : : void digestDNSMessage(HMACPtr hmac, uint16_t qid, const void* data,
147 : : size_t data_len) const;
148 : : State state_;
149 : : const TSIGKey key_;
150 : : vector<uint8_t> previous_digest_;
151 : : TSIGError error_;
152 : : uint64_t previous_timesigned_; // only meaningful for response with BADTIME
153 : : size_t digest_len_;
154 : : HMACPtr hmac_;
155 : : };
156 : :
157 : : void
158 : 143 : TSIGContext::TSIGContextImpl::digestPreviousMAC(HMACPtr hmac) const {
159 : : // We should have ensured the digest size fits 16 bits within this class
160 : : // implementation.
161 [ - + ]: 143 : assert(previous_digest_.size() <= 0xffff);
162 : :
163 : 143 : OutputBuffer buffer(sizeof(uint16_t) + previous_digest_.size());
164 : 143 : const uint16_t previous_digest_len(previous_digest_.size());
165 [ + - ]: 143 : buffer.writeUint16(previous_digest_len);
166 [ + + ]: 143 : if (previous_digest_len != 0) {
167 [ + - ]: 142 : buffer.writeData(&previous_digest_[0], previous_digest_len);
168 : : }
169 [ + - ]: 143 : hmac->update(buffer.getData(), buffer.getLength());
170 : 143 : }
171 : :
172 : : void
173 : 252 : TSIGContext::TSIGContextImpl::digestTSIGVariables(
174 : : HMACPtr hmac, uint16_t rrclass, uint32_t rrttl, uint64_t time_signed,
175 : : uint16_t fudge, uint16_t error, uint16_t otherlen, const void* otherdata,
176 : : bool time_variables_only) const
177 : : {
178 : : // It's bit complicated, but we can still predict the necessary size of
179 : : // the data to be digested. So we precompute it to avoid possible
180 : : // reallocation inside OutputBuffer (not absolutely necessary, but this
181 : : // is a bit more efficient)
182 : 252 : size_t data_size = 8;
183 [ + + ]: 252 : if (!time_variables_only) {
184 : 148 : data_size += 10 + key_.getKeyName().getLength() +
185 : 148 : key_.getAlgorithmName().getLength();
186 : : }
187 : 252 : OutputBuffer buffer(data_size);
188 : :
189 [ + + ]: 252 : if (!time_variables_only) {
190 [ + - ][ + - ]: 148 : key_.getKeyName().toWire(buffer);
191 [ + - ]: 148 : buffer.writeUint16(rrclass);
192 [ + - ]: 148 : buffer.writeUint32(rrttl);
193 [ + - ][ + - ]: 148 : key_.getAlgorithmName().toWire(buffer);
194 : : }
195 [ + - ]: 252 : buffer.writeUint16(time_signed >> 32);
196 [ + - ]: 252 : buffer.writeUint32(time_signed & 0xffffffff);
197 [ + - ]: 252 : buffer.writeUint16(fudge);
198 : :
199 [ + + ]: 252 : if (!time_variables_only) {
200 [ + - ]: 148 : buffer.writeUint16(error);
201 [ + - ]: 148 : buffer.writeUint16(otherlen);
202 : : }
203 : :
204 [ + - ]: 252 : hmac->update(buffer.getData(), buffer.getLength());
205 [ + + ][ + + ]: 252 : if (!time_variables_only && otherlen > 0) {
206 [ + - ]: 2 : hmac->update(otherdata, otherlen);
207 : : }
208 : 252 : }
209 : :
210 : : // In digestDNSMessage, we exploit some minimum knowledge of DNS message
211 : : // format:
212 : : // - the header section has a fixed length of 12 octets (MESSAGE_HEADER_LEN)
213 : : // - the offset in the header section to the ID field is 0
214 : : // - the offset in the header section to the ARCOUNT field is 10 (and the field
215 : : // length is 2 octets)
216 : : // We could construct a separate Message object from the given data, adjust
217 : : // fields via the Message interfaces and then render it back to a separate
218 : : // buffer, but that would be overkilling. The DNS message header has a
219 : : // fixed length and necessary modifications are quite straightforward, so
220 : : // we do the job using lower level interfaces.
221 : : namespace {
222 : : const size_t MESSAGE_HEADER_LEN = 12;
223 : : }
224 : : void
225 : 58 : TSIGContext::TSIGContextImpl::digestDNSMessage(HMACPtr hmac,
226 : : uint16_t qid, const void* data,
227 : : size_t data_len) const
228 : : {
229 : 58 : OutputBuffer buffer(MESSAGE_HEADER_LEN);
230 : 58 : const uint8_t* msgptr = static_cast<const uint8_t*>(data);
231 : :
232 : : // Install the original ID
233 [ + - ]: 58 : buffer.writeUint16(qid);
234 : 58 : msgptr += sizeof(uint16_t);
235 : :
236 : : // Copy the rest of the header except the ARCOUNT field.
237 [ + - ]: 58 : buffer.writeData(msgptr, 8);
238 : 58 : msgptr += 8;
239 : :
240 : : // Install the adjusted ARCOUNT (we don't care even if the value is bogus
241 : : // and it underflows; it would simply result in verification failure)
242 [ + - ]: 58 : buffer.writeUint16(InputBuffer(msgptr, sizeof(uint16_t)).readUint16() - 1);
243 : 58 : msgptr += 2;
244 : :
245 : : // Digest the header and the rest of the DNS message
246 [ + - ]: 58 : hmac->update(buffer.getData(), buffer.getLength());
247 [ + - ]: 58 : hmac->update(msgptr, data_len - MESSAGE_HEADER_LEN);
248 : 58 : }
249 : :
250 [ + - ]: 269 : TSIGContext::TSIGContext(const TSIGKey& key) : impl_(new TSIGContextImpl(key))
251 : : {
252 : 269 : }
253 : :
254 : 34 : TSIGContext::TSIGContext(const Name& key_name, const Name& algorithm_name,
255 : 34 : const TSIGKeyRing& keyring) : impl_(NULL)
256 : : {
257 : : const TSIGKeyRing::FindResult result(keyring.find(key_name,
258 : 34 : algorithm_name));
259 [ + + ]: 34 : if (result.code == TSIGKeyRing::NOTFOUND) {
260 : : // If not key is found, create a dummy key with the specified key
261 : : // parameters and empty secret. In the common scenario this will
262 : : // be used in subsequent response with a TSIG indicating a BADKEY
263 : : // error.
264 : : impl_ = new TSIGContextImpl(TSIGKey(key_name, algorithm_name,
265 [ + - ][ + - ]: 16 : NULL, 0), TSIGError::BAD_KEY());
266 : : } else {
267 [ + - ]: 18 : impl_ = new TSIGContextImpl(*result.key);
268 : : }
269 : 34 : }
270 : :
271 : 303 : TSIGContext::~TSIGContext() {
272 [ + - ]: 606 : delete impl_;
273 : 303 : }
274 : :
275 : : size_t
276 : 171 : TSIGContext::getTSIGLength() const {
277 : : //
278 : : // The space required for an TSIG record is:
279 : : //
280 : : // n1 bytes for the (key) name
281 : : // 2 bytes for the type
282 : : // 2 bytes for the class
283 : : // 4 bytes for the ttl
284 : : // 2 bytes for the rdlength
285 : : // n2 bytes for the algorithm name
286 : : // 6 bytes for the time signed
287 : : // 2 bytes for the fudge
288 : : // 2 bytes for the MAC size
289 : : // x bytes for the MAC
290 : : // 2 bytes for the original id
291 : : // 2 bytes for the error
292 : : // 2 bytes for the other data length
293 : : // y bytes for the other data (at most)
294 : : // ---------------------------------
295 : : // 26 + n1 + n2 + x + y bytes
296 : : //
297 : :
298 : : // Normally the digest length ("x") is the length of the underlying
299 : : // hash output. If a key related error occurred, however, the
300 : : // corresponding TSIG will be "unsigned", and the digest length will be 0.
301 : : const size_t digest_len =
302 : 171 : (impl_->error_ == TSIGError::BAD_KEY() ||
303 [ + + ][ + + ]: 171 : impl_->error_ == TSIGError::BAD_SIG()) ? 0 : impl_->digest_len_;
304 : :
305 : : // Other Len ("y") is normally 0; if BAD_TIME error occurred, the
306 : : // subsequent TSIG will contain 48 bits of the server current time.
307 [ + + ]: 171 : const size_t other_len = (impl_->error_ == TSIGError::BAD_TIME()) ? 6 : 0;
308 : :
309 : 171 : return (26 + impl_->key_.getKeyName().getLength() +
310 : 171 : impl_->key_.getAlgorithmName().getLength() +
311 : 171 : digest_len + other_len);
312 : : }
313 : :
314 : : TSIGContext::State
315 : 132 : TSIGContext::getState() const {
316 : 132 : return (impl_->state_);
317 : : }
318 : :
319 : : TSIGError
320 : 58 : TSIGContext::getError() const {
321 : 58 : return (impl_->error_);
322 : : }
323 : :
324 : : ConstTSIGRecordPtr
325 : 205 : TSIGContext::sign(const uint16_t qid, const void* const data,
326 : : const size_t data_len)
327 : : {
328 [ + + ]: 205 : if (impl_->state_ == VERIFIED_RESPONSE) {
329 [ + - ]: 4 : isc_throw(TSIGContextError,
330 : : "TSIG sign attempt after verifying a response");
331 : : }
332 : :
333 [ + + ]: 203 : if (data == NULL || data_len == 0) {
334 [ + - ]: 4 : isc_throw(InvalidParameter, "TSIG sign error: empty data is given");
335 : : }
336 : :
337 : 201 : TSIGError error(TSIGError::NOERROR());
338 : 201 : const uint64_t now = getTSIGTime();
339 : :
340 : : // For responses adjust the error code.
341 [ + + ]: 201 : if (impl_->state_ == RECEIVED_REQUEST) {
342 : 24 : error = impl_->error_;
343 : : }
344 : :
345 : : // For errors related to key or MAC, return an unsigned response as
346 : : // specified in Section 4.3 of RFC2845.
347 [ + + ][ + + ]: 201 : if (error == TSIGError::BAD_SIG() || error == TSIGError::BAD_KEY()) {
[ + + ]
348 : : ConstTSIGRecordPtr tsig(new TSIGRecord(
349 : 7 : impl_->key_.getKeyName(),
350 : 7 : any::TSIG(impl_->key_.getAlgorithmName(),
351 : : now, DEFAULT_FUDGE, 0, NULL,
352 [ + - ][ + - ]: 14 : qid, error.getCode(), 0, NULL)));
[ + - ][ + - ]
353 : 7 : impl_->previous_digest_.clear();
354 : 7 : impl_->state_ = SENT_RESPONSE;
355 : : return (tsig);
356 : : }
357 : :
358 : 194 : HMACPtr hmac(impl_->createHMAC());
359 : :
360 : : // If the context has previous MAC (either the Request MAC or its own
361 : : // previous MAC), digest it.
362 [ + + ]: 194 : if (impl_->state_ != INIT) {
363 [ + - ]: 123 : impl_->digestPreviousMAC(hmac);
364 : : }
365 : :
366 : : // Digest the message (without TSIG)
367 [ + - ]: 194 : hmac->update(data, data_len);
368 : :
369 : : // Digest TSIG variables.
370 : : // First, prepare some non constant variables.
371 : 194 : const uint64_t time_signed = (error == TSIGError::BAD_TIME()) ?
372 [ + + ]: 194 : impl_->previous_timesigned_ : now;
373 : : // For BADTIME error, we include 6 bytes of other data.
374 : : // (6 bytes = size of time signed value)
375 [ + + ]: 194 : const uint16_t otherlen = (error == TSIGError::BAD_TIME()) ? 6 : 0;
376 [ + - ]: 194 : OutputBuffer otherdatabuf(otherlen);
377 [ + + ]: 194 : if (error == TSIGError::BAD_TIME()) {
378 [ + - ]: 2 : otherdatabuf.writeUint16(now >> 32);
379 [ + - ]: 2 : otherdatabuf.writeUint32(now & 0xffffffff);
380 : : }
381 : : const void* const otherdata =
382 [ + + ]: 194 : (otherlen == 0) ? NULL : otherdatabuf.getData();
383 : : // Then calculate the digest. If state_ is SENT_RESPONSE we are sending
384 : : // a continued message in the same TCP stream so skip digesting
385 : : // variables except for time related variables (RFC2845 4.4).
386 [ + - ]: 194 : impl_->digestTSIGVariables(hmac, TSIGRecord::getClass().getCode(),
387 : : TSIGRecord::TSIG_TTL, time_signed,
388 : : DEFAULT_FUDGE, error.getCode(),
389 : : otherlen, otherdata,
390 [ + - ]: 194 : impl_->state_ == SENT_RESPONSE);
391 : :
392 : : // Get the final digest, update internal state, then finish.
393 [ + - ]: 388 : vector<uint8_t> digest = hmac->sign();
394 [ - + ]: 194 : assert(digest.size() <= 0xffff); // cryptolink API should have ensured it.
395 : : ConstTSIGRecordPtr tsig(new TSIGRecord(
396 : 194 : impl_->key_.getKeyName(),
397 [ + - ]: 194 : any::TSIG(impl_->key_.getAlgorithmName(),
398 : : time_signed, DEFAULT_FUDGE,
399 : 194 : digest.size(), &digest[0],
400 : : qid, error.getCode(), otherlen,
401 [ + - ][ + - ]: 388 : otherdata)));
[ + - ][ + - ]
[ + - ][ + - ]
402 : : // Exception free from now on.
403 : 194 : impl_->previous_digest_.swap(digest);
404 [ + + ]: 194 : impl_->state_ = (impl_->state_ == INIT) ? SENT_REQUEST : SENT_RESPONSE;
405 : : return (tsig);
406 : : }
407 : :
408 : : TSIGError
409 : 112 : TSIGContext::verify(const TSIGRecord* const record, const void* const data,
410 : : const size_t data_len)
411 : : {
412 [ + + ]: 112 : if (impl_->state_ == SENT_RESPONSE) {
413 [ + - ]: 4 : isc_throw(TSIGContextError,
414 : : "TSIG verify attempt after sending a response");
415 : : }
416 : :
417 : : // This case happens when we sent a signed request and have received an
418 : : // unsigned response. According to RFC2845 Section 4.6 this case should be
419 : : // considered a "format error" (although the specific error code
420 : : // wouldn't matter much for the caller).
421 [ + + ]: 110 : if (record == NULL) {
422 : 21 : return (impl_->postVerifyUpdate(TSIGError::FORMERR(), NULL, 0));
423 : : }
424 : :
425 : 89 : const any::TSIG& tsig_rdata = record->getRdata();
426 : :
427 : : // Reject some obviously invalid data
428 [ + + ]: 89 : if (data_len < MESSAGE_HEADER_LEN + record->getLength()) {
429 [ + - ]: 6 : isc_throw(InvalidParameter,
430 : : "TSIG verify: data length is invalid: " << data_len);
431 : : }
432 [ + + ]: 87 : if (data == NULL) {
433 [ + - ]: 2 : isc_throw(InvalidParameter, "TSIG verify: empty data is invalid");
434 : : }
435 : :
436 : : // Check key: whether we first verify it with a known key or we verify
437 : : // it using the consistent key in the context. If the check fails we are
438 : : // done with BADKEY.
439 [ + + ][ + + ]: 86 : if (impl_->state_ == INIT && impl_->error_ == TSIGError::BAD_KEY()) {
[ + + ]
440 : 7 : return (impl_->postVerifyUpdate(TSIGError::BAD_KEY(), NULL, 0));
441 : : }
442 [ + + + + ]: 235 : if (impl_->key_.getKeyName() != record->getName() ||
[ + + ]
443 : 77 : impl_->key_.getAlgorithmName() != tsig_rdata.getAlgorithm()) {
444 : 4 : return (impl_->postVerifyUpdate(TSIGError::BAD_KEY(), NULL, 0));
445 : : }
446 : :
447 : : // Check time: the current time must be in the range of
448 : : // [time signed - fudge, time signed + fudge]. Otherwise verification
449 : : // fails with BADTIME. (RFC2845 Section 4.6.2)
450 : : // Note: for simplicity we don't explicitly catch the case of too small
451 : : // current time causing underflow. With the fact that fudge is quite
452 : : // small and (for now) non configurable, it shouldn't be a real concern
453 : : // in practice.
454 : 75 : const uint64_t now = getTSIGTime();
455 [ + + + + ]: 144 : if (tsig_rdata.getTimeSigned() + DEFAULT_FUDGE < now ||
[ + + ]
456 : 69 : tsig_rdata.getTimeSigned() - DEFAULT_FUDGE > now) {
457 : 13 : const void* digest = NULL;
458 : 13 : size_t digest_len = 0;
459 [ + + ]: 13 : if (impl_->state_ == INIT) {
460 : 9 : digest = tsig_rdata.getMAC();
461 : 9 : digest_len = tsig_rdata.getMACSize();
462 : 9 : impl_->previous_timesigned_ = tsig_rdata.getTimeSigned();
463 : : }
464 : 13 : return (impl_->postVerifyUpdate(TSIGError::BAD_TIME(), digest,
465 : 13 : digest_len));
466 : : }
467 : :
468 : : // TODO: signature length check based on RFC4635
469 : : // (Right now we enforce the standard signature length in libcryptolink)
470 : :
471 : : // Handling empty MAC. While RFC2845 doesn't explicitly prohibit other
472 : : // cases, it can only reasonably happen in a response with BADSIG or
473 : : // BADKEY. We reject other cases as if it were BADSIG to avoid unexpected
474 : : // acceptance of a bogus signature. This behavior follows the BIND 9
475 : : // implementation.
476 [ + + ]: 62 : if (tsig_rdata.getMACSize() == 0) {
477 : 4 : TSIGError error = TSIGError(tsig_rdata.getError());
478 [ + - ][ + + ]: 4 : if (error != TSIGError::BAD_SIG() && error != TSIGError::BAD_KEY()) {
[ + + ]
479 : 2 : error = TSIGError::BAD_SIG();
480 : : }
481 : 4 : return (impl_->postVerifyUpdate(error, NULL, 0));
482 : : }
483 : :
484 : 58 : HMACPtr hmac(impl_->createHMAC());
485 : :
486 : : // If the context has previous MAC (either the Request MAC or its own
487 : : // previous MAC), digest it.
488 [ + + ]: 58 : if (impl_->state_ != INIT) {
489 [ + - ]: 20 : impl_->digestPreviousMAC(hmac);
490 : : }
491 : :
492 : : //
493 : : // Digest DNS message (excluding the trailing TSIG RR and adjusting the
494 : : // QID and ARCOUNT header fields)
495 : : //
496 [ + - ]: 58 : impl_->digestDNSMessage(hmac, tsig_rdata.getOriginalID(),
497 [ + - ]: 58 : data, data_len - record->getLength());
498 : :
499 : : // Digest TSIG variables. If state_ is VERIFIED_RESPONSE, it's a
500 : : // continuation of the same TCP stream and skip digesting them except
501 : : // for time related variables (RFC2845 4.4).
502 : : // Note: we use the constant values for RR class and TTL specified
503 : : // in RFC2845, not received values (we reject other values in constructing
504 : : // the TSIGRecord).
505 [ + - ]: 58 : impl_->digestTSIGVariables(hmac, TSIGRecord::getClass().getCode(),
506 : : TSIGRecord::TSIG_TTL,
507 : : tsig_rdata.getTimeSigned(),
508 [ + - ][ + - ]: 58 : tsig_rdata.getFudge(), tsig_rdata.getError(),
509 [ + - ]: 58 : tsig_rdata.getOtherLen(),
510 : : tsig_rdata.getOtherData(),
511 [ + - ][ + - ]: 174 : impl_->state_ == VERIFIED_RESPONSE);
[ + - ]
512 : :
513 : : // Verify the digest with the received signature.
514 [ + - ][ + - ]: 58 : if (hmac->verify(tsig_rdata.getMAC(), tsig_rdata.getMACSize())) {
[ + - ][ + + ]
515 [ + - ]: 45 : return (impl_->postVerifyUpdate(TSIGError::NOERROR(),
516 : : tsig_rdata.getMAC(),
517 [ + - ][ + - ]: 90 : tsig_rdata.getMACSize()));
[ + - ]
518 : : }
519 : :
520 [ + - ]: 13 : return (impl_->postVerifyUpdate(TSIGError::BAD_SIG(), NULL, 0));
521 : : }
522 : :
523 : : } // namespace dns
524 : 137 : } // namespace isc
|