dnskey_48.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <iostream>
  8. #include <string>
  9. #include <sstream>
  10. #include <vector>
  11. #include <boost/lexical_cast.hpp>
  12. #include <boost/foreach.hpp>
  13. #include <util/encode/base64.h>
  14. #include <util/buffer.h>
  15. #include <dns/messagerenderer.h>
  16. #include <dns/name.h>
  17. #include <dns/rdata.h>
  18. #include <dns/rdataclass.h>
  19. #include <memory>
  20. #include <stdio.h>
  21. #include <time.h>
  22. using namespace std;
  23. using namespace isc::util;
  24. using namespace isc::util::encode;
  25. // BEGIN_ISC_NAMESPACE
  26. // BEGIN_RDATA_NAMESPACE
  27. struct DNSKEYImpl {
  28. // straightforward representation of DNSKEY RDATA fields
  29. DNSKEYImpl(uint16_t flags, uint8_t protocol, uint8_t algorithm,
  30. const vector<uint8_t>& keydata) :
  31. flags_(flags), protocol_(protocol), algorithm_(algorithm),
  32. keydata_(keydata)
  33. {}
  34. uint16_t flags_;
  35. uint8_t protocol_;
  36. uint8_t algorithm_;
  37. const vector<uint8_t> keydata_;
  38. };
  39. /// \brief Constructor from string.
  40. ///
  41. /// The given string must represent a valid DNSKEY RDATA. There can be
  42. /// extra space characters at the beginning or end of the text (which
  43. /// are simply ignored), but other extra text, including a new line,
  44. /// will make the construction fail with an exception.
  45. ///
  46. /// The Protocol and Algorithm fields must be within their valid
  47. /// ranges. The Public Key field must be present and must contain a
  48. /// Base64 encoding of the public key. Whitespace is allowed within the
  49. /// Base64 text.
  50. ///
  51. /// It is okay for the key data to be missing. Note: BIND 9 also accepts
  52. /// DNSKEY missing key data. While the RFC is silent in this case, and it
  53. /// may be debatable what an implementation should do, but since this field
  54. /// is algorithm dependent and this implementations doesn't reject unknown
  55. /// algorithms, it's lenient here.
  56. ///
  57. /// \throw InvalidRdataText if any fields are out of their valid range,
  58. /// or are incorrect.
  59. ///
  60. /// \param dnskey_str A string containing the RDATA to be created
  61. DNSKEY::DNSKEY(const std::string& dnskey_str) :
  62. impl_(NULL)
  63. {
  64. // We use unique_ptr here because if there is an exception in this
  65. // constructor, the destructor is not called and there could be a
  66. // leak of the DNSKEYImpl that constructFromLexer() returns.
  67. std::unique_ptr<DNSKEYImpl> impl_ptr;
  68. try {
  69. std::istringstream ss(dnskey_str);
  70. MasterLexer lexer;
  71. lexer.pushSource(ss);
  72. impl_ptr.reset(constructFromLexer(lexer));
  73. if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
  74. isc_throw(InvalidRdataText,
  75. "Extra input text for DNSKEY: " << dnskey_str);
  76. }
  77. } catch (const MasterLexer::LexerError& ex) {
  78. isc_throw(InvalidRdataText,
  79. "Failed to construct DNSKEY from '" << dnskey_str << "': "
  80. << ex.what());
  81. }
  82. impl_ = impl_ptr.release();
  83. }
  84. /// \brief Constructor from InputBuffer.
  85. ///
  86. /// The passed buffer must contain a valid DNSKEY RDATA.
  87. ///
  88. /// The Protocol and Algorithm fields are not checked for unknown
  89. /// values. It is okay for the key data to be missing (see the description
  90. /// of the constructor from string).
  91. DNSKEY::DNSKEY(InputBuffer& buffer, size_t rdata_len) :
  92. impl_(NULL)
  93. {
  94. if (rdata_len < 4) {
  95. isc_throw(InvalidRdataLength, "DNSKEY too short: " << rdata_len);
  96. }
  97. const uint16_t flags = buffer.readUint16();
  98. const uint16_t protocol = buffer.readUint8();
  99. const uint16_t algorithm = buffer.readUint8();
  100. rdata_len -= 4;
  101. vector<uint8_t> keydata;
  102. // If key data is missing, it's OK. See the API documentation of the
  103. // constructor.
  104. if (rdata_len > 0) {
  105. keydata.resize(rdata_len);
  106. buffer.readData(&keydata[0], rdata_len);
  107. }
  108. impl_ = new DNSKEYImpl(flags, protocol, algorithm, keydata);
  109. }
  110. /// \brief Constructor with a context of MasterLexer.
  111. ///
  112. /// The \c lexer should point to the beginning of valid textual
  113. /// representation of an DNSKEY RDATA.
  114. ///
  115. /// See \c DNSKEY::DNSKEY(const std::string&) for description of the
  116. /// expected RDATA fields.
  117. ///
  118. /// \throw MasterLexer::LexerError General parsing error such as
  119. /// missing field.
  120. /// \throw InvalidRdataText if any fields are out of their valid range,
  121. /// or are incorrect.
  122. ///
  123. /// \param lexer A \c MasterLexer object parsing a master file for the
  124. /// RDATA to be created
  125. DNSKEY::DNSKEY(MasterLexer& lexer, const Name*,
  126. MasterLoader::Options, MasterLoaderCallbacks&) :
  127. impl_(NULL)
  128. {
  129. impl_ = constructFromLexer(lexer);
  130. }
  131. DNSKEYImpl*
  132. DNSKEY::constructFromLexer(MasterLexer& lexer) {
  133. const uint32_t flags = lexer.getNextToken(MasterToken::NUMBER).getNumber();
  134. if (flags > 0xffff) {
  135. isc_throw(InvalidRdataText,
  136. "DNSKEY flags out of range: " << flags);
  137. }
  138. const uint32_t protocol =
  139. lexer.getNextToken(MasterToken::NUMBER).getNumber();
  140. if (protocol > 0xff) {
  141. isc_throw(InvalidRdataText,
  142. "DNSKEY protocol out of range: " << protocol);
  143. }
  144. const uint32_t algorithm =
  145. lexer.getNextToken(MasterToken::NUMBER).getNumber();
  146. if (algorithm > 0xff) {
  147. isc_throw(InvalidRdataText,
  148. "DNSKEY algorithm out of range: " << algorithm);
  149. }
  150. std::string keydata_str;
  151. std::string keydata_substr;
  152. while (true) {
  153. const MasterToken& token =
  154. lexer.getNextToken(MasterToken::STRING, true);
  155. if ((token.getType() == MasterToken::END_OF_FILE) ||
  156. (token.getType() == MasterToken::END_OF_LINE)) {
  157. break;
  158. }
  159. // token is now assured to be of type STRING.
  160. token.getString(keydata_substr);
  161. keydata_str.append(keydata_substr);
  162. }
  163. lexer.ungetToken();
  164. vector<uint8_t> keydata;
  165. // If key data is missing, it's OK. See the API documentation of the
  166. // constructor.
  167. if (keydata_str.size() > 0) {
  168. decodeBase64(keydata_str, keydata);
  169. }
  170. return (new DNSKEYImpl(flags, protocol, algorithm, keydata));
  171. }
  172. DNSKEY::DNSKEY(const DNSKEY& source) :
  173. Rdata(), impl_(new DNSKEYImpl(*source.impl_))
  174. {}
  175. DNSKEY&
  176. DNSKEY::operator=(const DNSKEY& source) {
  177. if (this == &source) {
  178. return (*this);
  179. }
  180. DNSKEYImpl* newimpl = new DNSKEYImpl(*source.impl_);
  181. delete impl_;
  182. impl_ = newimpl;
  183. return (*this);
  184. }
  185. DNSKEY::~DNSKEY() {
  186. delete impl_;
  187. }
  188. string
  189. DNSKEY::toText() const {
  190. return (boost::lexical_cast<string>(static_cast<int>(impl_->flags_)) +
  191. " " + boost::lexical_cast<string>(static_cast<int>(impl_->protocol_)) +
  192. " " + boost::lexical_cast<string>(static_cast<int>(impl_->algorithm_)) +
  193. " " + encodeBase64(impl_->keydata_));
  194. }
  195. void
  196. DNSKEY::toWire(OutputBuffer& buffer) const {
  197. buffer.writeUint16(impl_->flags_);
  198. buffer.writeUint8(impl_->protocol_);
  199. buffer.writeUint8(impl_->algorithm_);
  200. buffer.writeData(&impl_->keydata_[0], impl_->keydata_.size());
  201. }
  202. void
  203. DNSKEY::toWire(AbstractMessageRenderer& renderer) const {
  204. renderer.writeUint16(impl_->flags_);
  205. renderer.writeUint8(impl_->protocol_);
  206. renderer.writeUint8(impl_->algorithm_);
  207. renderer.writeData(&impl_->keydata_[0], impl_->keydata_.size());
  208. }
  209. int
  210. DNSKEY::compare(const Rdata& other) const {
  211. const DNSKEY& other_dnskey = dynamic_cast<const DNSKEY&>(other);
  212. if (impl_->flags_ != other_dnskey.impl_->flags_) {
  213. return (impl_->flags_ < other_dnskey.impl_->flags_ ? -1 : 1);
  214. }
  215. if (impl_->protocol_ != other_dnskey.impl_->protocol_) {
  216. return (impl_->protocol_ < other_dnskey.impl_->protocol_ ? -1 : 1);
  217. }
  218. if (impl_->algorithm_ != other_dnskey.impl_->algorithm_) {
  219. return (impl_->algorithm_ < other_dnskey.impl_->algorithm_ ? -1 : 1);
  220. }
  221. const size_t this_len = impl_->keydata_.size();
  222. const size_t other_len = other_dnskey.impl_->keydata_.size();
  223. const size_t cmplen = min(this_len, other_len);
  224. if (cmplen == 0) {
  225. return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1);
  226. }
  227. const int cmp = memcmp(&impl_->keydata_[0],
  228. &other_dnskey.impl_->keydata_[0], cmplen);
  229. if (cmp != 0) {
  230. return (cmp);
  231. } else {
  232. return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1);
  233. }
  234. }
  235. uint16_t
  236. DNSKEY::getTag() const {
  237. if (impl_->algorithm_ == 1) {
  238. // See RFC 4034 appendix B.1 for why the key data must contain
  239. // at least 4 bytes with RSA/MD5: 3 trailing bytes to extract
  240. // the tag from, and 1 byte of exponent length subfield before
  241. // modulus.
  242. const int len = impl_->keydata_.size();
  243. if (len < 4) {
  244. isc_throw(isc::OutOfRange,
  245. "DNSKEY keydata too short for tag extraction");
  246. }
  247. return ((impl_->keydata_[len - 3] << 8) + impl_->keydata_[len - 2]);
  248. }
  249. uint32_t ac = impl_->flags_;
  250. ac += (impl_->protocol_ << 8);
  251. ac += impl_->algorithm_;
  252. const size_t size = impl_->keydata_.size();
  253. for (size_t i = 0; i < size; i ++) {
  254. ac += (i & 1) ? impl_->keydata_[i] : (impl_->keydata_[i] << 8);
  255. }
  256. ac += (ac >> 16) & 0xffff;
  257. return (ac & 0xffff);
  258. }
  259. uint16_t
  260. DNSKEY::getFlags() const {
  261. return (impl_->flags_);
  262. }
  263. uint8_t
  264. DNSKEY::getAlgorithm() const {
  265. return (impl_->algorithm_);
  266. }
  267. // END_RDATA_NAMESPACE
  268. // END_ISC_NAMESPACE