tsig.cc 7.4 KB

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