tsig.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. #include <sys/time.h>
  15. #include <stdint.h>
  16. #include <cassert> // for the tentative verifyTentative()
  17. #include <vector>
  18. #include <boost/shared_ptr.hpp>
  19. #include <exceptions/exceptions.h>
  20. #include <util/buffer.h>
  21. #include <util/time_utilities.h>
  22. #include <dns/rdataclass.h>
  23. #include <dns/rrclass.h>
  24. #include <dns/tsig.h>
  25. #include <dns/tsigerror.h>
  26. #include <dns/tsigkey.h>
  27. #include <cryptolink/cryptolink.h>
  28. #include <cryptolink/crypto_hmac.h>
  29. using namespace std;
  30. using namespace isc::util;
  31. using namespace isc::cryptolink;
  32. using namespace isc::dns::rdata;
  33. namespace isc {
  34. namespace dns {
  35. namespace {
  36. typedef boost::shared_ptr<HMAC> HMACPtr;
  37. }
  38. struct TSIGContext::TSIGContextImpl {
  39. TSIGContextImpl(const TSIGKey& key) :
  40. state_(INIT), key_(key), error_(Rcode::NOERROR()),
  41. previous_timesigned_(0)
  42. {}
  43. State state_;
  44. TSIGKey key_;
  45. vector<uint8_t> previous_digest_;
  46. TSIGError error_;
  47. uint64_t previous_timesigned_; // only meaningful for response with BADTIME
  48. };
  49. TSIGContext::TSIGContext(const TSIGKey& key) : impl_(new TSIGContextImpl(key))
  50. {
  51. }
  52. TSIGContext::~TSIGContext() {
  53. delete impl_;
  54. }
  55. TSIGContext::State
  56. TSIGContext::getState() const {
  57. return (impl_->state_);
  58. }
  59. TSIGError
  60. TSIGContext::getError() const {
  61. return (impl_->error_);
  62. }
  63. ConstTSIGRecordPtr
  64. TSIGContext::sign(const uint16_t qid, const void* const data,
  65. const size_t data_len)
  66. {
  67. if (data == NULL || data_len == 0) {
  68. isc_throw(InvalidParameter, "TSIG sign error: empty data is given");
  69. }
  70. TSIGError error(TSIGError::NOERROR());
  71. // TSIG uses 48-bit unsigned integer to represent time signed.
  72. // Since gettimeofdayWrapper() returns a 64-bit *signed* integer, we
  73. // make sure it's stored in an unsigned 64-bit integer variable and
  74. // represents a value in the expected range. (In reality, however,
  75. // gettimeofdayWrapper() will return a positive integer that will fit
  76. // in 48 bits)
  77. const uint64_t now = (detail::gettimeWrapper() & 0x0000ffffffffffffULL);
  78. // For responses adjust the error code.
  79. if (impl_->state_ == CHECKED) {
  80. error = impl_->error_;
  81. }
  82. // For errors related to key or MAC, return an unsigned response as
  83. // specified in Section 4.3 of RFC2845.
  84. if (error == TSIGError::BAD_SIG() || error == TSIGError::BAD_KEY()) {
  85. ConstTSIGRecordPtr tsig(new TSIGRecord(
  86. impl_->key_.getKeyName(),
  87. any::TSIG(impl_->key_.getAlgorithmName(),
  88. now, DEFAULT_FUDGE, 0, NULL,
  89. qid, error.getCode(), 0, NULL)));
  90. impl_->previous_digest_.clear();
  91. impl_->state_ = SIGNED;
  92. return (tsig);
  93. }
  94. OutputBuffer variables(0);
  95. HMACPtr hmac(CryptoLink::getCryptoLink().createHMAC(
  96. impl_->key_.getSecret(),
  97. impl_->key_.getSecretLength(),
  98. impl_->key_.getAlgorithm()),
  99. deleteHMAC);
  100. // If the context has previous MAC (either the Request MAC or its own
  101. // previous MAC), digest it.
  102. if (impl_->state_ != INIT) {
  103. const uint16_t previous_digest_len(impl_->previous_digest_.size());
  104. variables.writeUint16(previous_digest_len);
  105. if (previous_digest_len != 0) {
  106. variables.writeData(&impl_->previous_digest_[0],
  107. previous_digest_len);
  108. }
  109. hmac->update(variables.getData(), variables.getLength());
  110. }
  111. // Digest the message (without TSIG)
  112. hmac->update(data, data_len);
  113. //
  114. // Digest TSIG variables. If state_ is SIGNED we skip digesting them
  115. // except for time related variables (RFC2845 4.4).
  116. //
  117. variables.clear();
  118. if (impl_->state_ != SIGNED) {
  119. impl_->key_.getKeyName().toWire(variables);
  120. TSIGRecord::getClass().toWire(variables);
  121. variables.writeUint32(TSIGRecord::TSIG_TTL);
  122. impl_->key_.getAlgorithmName().toWire(variables);
  123. }
  124. const uint64_t time_signed = (error == TSIGError::BAD_TIME()) ?
  125. impl_->previous_timesigned_ : now;
  126. variables.writeUint16(time_signed >> 32);
  127. variables.writeUint32(time_signed & 0xffffffff);
  128. variables.writeUint16(DEFAULT_FUDGE);
  129. hmac->update(variables.getData(), variables.getLength());
  130. variables.clear();
  131. if (impl_->state_ != SIGNED) {
  132. variables.writeUint16(error.getCode());
  133. // For BADTIME error, digest 6 bytes of other data.
  134. // (6 bytes = size of time signed value)
  135. variables.writeUint16((error == TSIGError::BAD_TIME()) ? 6 : 0);
  136. hmac->update(variables.getData(), variables.getLength());
  137. variables.clear();
  138. if (error == TSIGError::BAD_TIME()) {
  139. variables.writeUint16(now >> 32);
  140. variables.writeUint32(now & 0xffffffff);
  141. hmac->update(variables.getData(), variables.getLength());
  142. }
  143. }
  144. const uint16_t otherlen = variables.getLength();
  145. // Get the final digest, update internal state, then finish.
  146. vector<uint8_t> digest = hmac->sign();
  147. ConstTSIGRecordPtr tsig(new TSIGRecord(
  148. impl_->key_.getKeyName(),
  149. any::TSIG(impl_->key_.getAlgorithmName(),
  150. time_signed, DEFAULT_FUDGE,
  151. digest.size(), &digest[0],
  152. qid, error.getCode(), otherlen,
  153. otherlen == 0 ?
  154. NULL : variables.getData())));
  155. // Exception free from now on.
  156. impl_->previous_digest_.swap(digest);
  157. impl_->state_ = SIGNED;
  158. return (tsig);
  159. }
  160. void
  161. TSIGContext::verifyTentative(ConstTSIGRecordPtr tsig, TSIGError error) {
  162. const any::TSIG tsig_rdata = tsig->getRdata();
  163. impl_->error_ = error;
  164. if (error == TSIGError::BAD_TIME()) {
  165. impl_->previous_timesigned_ = tsig_rdata.getTimeSigned();
  166. }
  167. // For simplicity we assume non empty digests.
  168. assert(tsig_rdata.getMACSize() != 0);
  169. impl_->previous_digest_.assign(
  170. static_cast<const uint8_t*>(tsig_rdata.getMAC()),
  171. static_cast<const uint8_t*>(tsig_rdata.getMAC()) +
  172. tsig_rdata.getMACSize());
  173. impl_->state_ = CHECKED;
  174. }
  175. } // namespace dns
  176. } // namespace isc