sshfp_44.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright (C) 2012-2013 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 <config.h>
  15. #include <string>
  16. #include <boost/lexical_cast.hpp>
  17. #include <exceptions/exceptions.h>
  18. #include <util/buffer.h>
  19. #include <util/encode/hex.h>
  20. #include <dns/name.h>
  21. #include <dns/messagerenderer.h>
  22. #include <dns/rdata.h>
  23. #include <dns/rdataclass.h>
  24. using namespace std;
  25. using boost::lexical_cast;
  26. using namespace isc::util;
  27. using namespace isc::util::encode;
  28. // BEGIN_ISC_NAMESPACE
  29. // BEGIN_RDATA_NAMESPACE
  30. struct SSHFPImpl {
  31. // straightforward representation of SSHFP RDATA fields
  32. SSHFPImpl(uint8_t algorithm, uint8_t fingerprint_type,
  33. vector<uint8_t>& fingerprint) :
  34. algorithm_(algorithm),
  35. fingerprint_type_(fingerprint_type),
  36. fingerprint_(fingerprint)
  37. {}
  38. uint8_t algorithm_;
  39. uint8_t fingerprint_type_;
  40. const vector<uint8_t> fingerprint_;
  41. };
  42. // helper function for string and lexer constructors
  43. SSHFPImpl*
  44. SSHFP::constructFromLexer(MasterLexer& lexer) {
  45. const uint32_t algorithm =
  46. lexer.getNextToken(MasterToken::NUMBER).getNumber();
  47. if (algorithm > 255) {
  48. isc_throw(InvalidRdataText, "SSHFP algorithm number out of range");
  49. }
  50. const uint32_t fingerprint_type =
  51. lexer.getNextToken(MasterToken::NUMBER).getNumber();
  52. if (fingerprint_type > 255) {
  53. isc_throw(InvalidRdataText, "SSHFP fingerprint type out of range");
  54. }
  55. const MasterToken& token = lexer.getNextToken(MasterToken::STRING, true);
  56. vector<uint8_t> fingerprint;
  57. if ((token.getType() != MasterToken::END_OF_FILE) &&
  58. (token.getType() != MasterToken::END_OF_LINE)) {
  59. decodeHex(token.getString(), fingerprint);
  60. }
  61. return (new SSHFPImpl(algorithm, fingerprint_type, fingerprint));
  62. }
  63. /// \brief Constructor from string.
  64. ///
  65. /// The given string must represent a valid SSHFP RDATA. There can be
  66. /// extra space characters at the beginning or end of the text (which
  67. /// are simply ignored), but other extra text, including a new line,
  68. /// will make the construction fail with an exception.
  69. ///
  70. /// The Algorithm and Fingerprint Type fields must be within their valid
  71. /// ranges, but are not contrained to the values defined in RFC4255.
  72. ///
  73. /// The Fingerprint field may be absent, but if present it must contain a
  74. /// valid hex encoding of the fingerprint.
  75. ///
  76. /// \throw InvalidRdataText if any fields are missing, out of their valid
  77. /// ranges, or incorrect.
  78. ///
  79. /// \param sshfp_str A string containing the RDATA to be created
  80. SSHFP::SSHFP(const string& sshfp_str) :
  81. impl_(NULL)
  82. {
  83. // We use auto_ptr here because if there is an exception in this
  84. // constructor, the destructor is not called and there could be a
  85. // leak of the SSHFPImpl that constructFromLexer() returns.
  86. std::auto_ptr<SSHFPImpl> impl_ptr(NULL);
  87. try {
  88. std::istringstream ss(sshfp_str);
  89. MasterLexer lexer;
  90. lexer.pushSource(ss);
  91. impl_ptr.reset(constructFromLexer(lexer));
  92. if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
  93. isc_throw(InvalidRdataText, "extra input text for SSHFP: "
  94. << sshfp_str);
  95. }
  96. } catch (const MasterLexer::LexerError& ex) {
  97. isc_throw(InvalidRdataText, "Failed to construct SSHFP from '" <<
  98. sshfp_str << "': " << ex.what());
  99. } catch (const isc::BadValue& e) {
  100. isc_throw(InvalidRdataText,
  101. "Bad SSHFP fingerprint: " << e.what());
  102. }
  103. impl_ = impl_ptr.release();
  104. }
  105. /// \brief Constructor with a context of MasterLexer.
  106. ///
  107. /// The \c lexer should point to the beginning of valid textual representation
  108. /// of an SSHFP RDATA.
  109. ///
  110. /// \throw MasterLexer::LexerError General parsing error such as missing field.
  111. /// \throw InvalidRdataText Fields are out of their valid range, or are
  112. /// incorrect.
  113. /// \throw BadValue Fingerprint is not a valid hex string.
  114. ///
  115. /// \param lexer A \c MasterLexer object parsing a master file for the
  116. /// RDATA to be created
  117. SSHFP::SSHFP(MasterLexer& lexer, const Name*,
  118. MasterLoader::Options, MasterLoaderCallbacks&) :
  119. impl_(NULL)
  120. {
  121. impl_ = constructFromLexer(lexer);
  122. }
  123. /// \brief Constructor from InputBuffer.
  124. ///
  125. /// The passed buffer must contain a valid SSHFP RDATA.
  126. ///
  127. /// The Algorithm and Fingerprint Type fields are not checked for unknown
  128. /// values. It is okay for the fingerprint data to be missing (see the
  129. /// description of the constructor from string).
  130. SSHFP::SSHFP(InputBuffer& buffer, size_t rdata_len) {
  131. if (rdata_len < 2) {
  132. isc_throw(InvalidRdataLength, "SSHFP record too short");
  133. }
  134. const uint8_t algorithm = buffer.readUint8();
  135. const uint8_t fingerprint_type = buffer.readUint8();
  136. vector<uint8_t> fingerprint;
  137. rdata_len -= 2;
  138. if (rdata_len > 0) {
  139. fingerprint.resize(rdata_len);
  140. buffer.readData(&fingerprint[0], rdata_len);
  141. }
  142. impl_ = new SSHFPImpl(algorithm, fingerprint_type, fingerprint);
  143. }
  144. SSHFP::SSHFP(uint8_t algorithm, uint8_t fingerprint_type,
  145. const string& fingerprint_txt) :
  146. impl_(NULL)
  147. {
  148. vector<uint8_t> fingerprint;
  149. try {
  150. decodeHex(fingerprint_txt, fingerprint);
  151. } catch (const isc::BadValue& e) {
  152. isc_throw(InvalidRdataText, "Bad SSHFP fingerprint: " << e.what());
  153. }
  154. impl_ = new SSHFPImpl(algorithm, fingerprint_type, fingerprint);
  155. }
  156. SSHFP::SSHFP(const SSHFP& other) :
  157. Rdata(), impl_(new SSHFPImpl(*other.impl_))
  158. {}
  159. SSHFP::~SSHFP() {
  160. delete impl_;
  161. }
  162. void
  163. SSHFP::toWire(OutputBuffer& buffer) const {
  164. buffer.writeUint8(impl_->algorithm_);
  165. buffer.writeUint8(impl_->fingerprint_type_);
  166. if (!impl_->fingerprint_.empty()) {
  167. buffer.writeData(&impl_->fingerprint_[0],
  168. impl_->fingerprint_.size());
  169. }
  170. }
  171. void
  172. SSHFP::toWire(AbstractMessageRenderer& renderer) const {
  173. renderer.writeUint8(impl_->algorithm_);
  174. renderer.writeUint8(impl_->fingerprint_type_);
  175. if (!impl_->fingerprint_.empty()) {
  176. renderer.writeData(&impl_->fingerprint_[0],
  177. impl_->fingerprint_.size());
  178. }
  179. }
  180. string
  181. SSHFP::toText() const {
  182. return (lexical_cast<string>(static_cast<int>(impl_->algorithm_)) + " " +
  183. lexical_cast<string>(static_cast<int>(impl_->fingerprint_type_)) +
  184. (impl_->fingerprint_.empty() ? "" :
  185. " " + encodeHex(impl_->fingerprint_)));
  186. }
  187. int
  188. SSHFP::compare(const Rdata& other) const {
  189. const SSHFP& other_sshfp = dynamic_cast<const SSHFP&>(other);
  190. if (impl_->algorithm_ < other_sshfp.impl_->algorithm_) {
  191. return (-1);
  192. } else if (impl_->algorithm_ > other_sshfp.impl_->algorithm_) {
  193. return (1);
  194. }
  195. if (impl_->fingerprint_type_ < other_sshfp.impl_->fingerprint_type_) {
  196. return (-1);
  197. } else if (impl_->fingerprint_type_ >
  198. other_sshfp.impl_->fingerprint_type_) {
  199. return (1);
  200. }
  201. const size_t this_len = impl_->fingerprint_.size();
  202. const size_t other_len = other_sshfp.impl_->fingerprint_.size();
  203. const size_t cmplen = min(this_len, other_len);
  204. if (cmplen > 0) {
  205. const int cmp = memcmp(&impl_->fingerprint_[0],
  206. &other_sshfp.impl_->fingerprint_[0],
  207. cmplen);
  208. if (cmp != 0) {
  209. return (cmp);
  210. }
  211. }
  212. if (this_len == other_len) {
  213. return (0);
  214. } else if (this_len < other_len) {
  215. return (-1);
  216. } else {
  217. return (1);
  218. }
  219. }
  220. uint8_t
  221. SSHFP::getAlgorithmNumber() const {
  222. return (impl_->algorithm_);
  223. }
  224. uint8_t
  225. SSHFP::getFingerprintType() const {
  226. return (impl_->fingerprint_type_);
  227. }
  228. size_t
  229. SSHFP::getFingerprintLen() const {
  230. return (impl_->fingerprint_.size());
  231. }
  232. // END_RDATA_NAMESPACE
  233. // END_ISC_NAMESPACE