sshfp_44.cc 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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. std::string fingerprint_str;
  56. std::string fingerprint_substr;
  57. while (true) {
  58. const MasterToken& token =
  59. lexer.getNextToken(MasterToken::STRING, true);
  60. if ((token.getType() == MasterToken::END_OF_FILE) ||
  61. (token.getType() == MasterToken::END_OF_LINE)) {
  62. break;
  63. }
  64. token.getString(fingerprint_substr);
  65. fingerprint_str.append(fingerprint_substr);
  66. }
  67. lexer.ungetToken();
  68. vector<uint8_t> fingerprint;
  69. // If fingerprint is missing, it's OK. See the API documentation of the
  70. // constructor.
  71. if (fingerprint_str.size() > 0) {
  72. decodeHex(fingerprint_str, fingerprint);
  73. }
  74. return (new SSHFPImpl(algorithm, fingerprint_type, fingerprint));
  75. }
  76. /// \brief Constructor from string.
  77. ///
  78. /// The given string must represent a valid SSHFP RDATA. There can be
  79. /// extra space characters at the beginning or end of the text (which
  80. /// are simply ignored), but other extra text, including a new line,
  81. /// will make the construction fail with an exception.
  82. ///
  83. /// The Algorithm and Fingerprint Type fields must be within their valid
  84. /// ranges, but are not constrained to the values defined in RFC4255.
  85. ///
  86. /// The Fingerprint field may be absent, but if present it must contain a
  87. /// valid hex encoding of the fingerprint. For compatibility with BIND 9,
  88. /// whitespace is allowed in the hex text (RFC4255 is silent on the matter).
  89. ///
  90. /// \throw InvalidRdataText if any fields are missing, out of their valid
  91. /// ranges, or incorrect.
  92. ///
  93. /// \param sshfp_str A string containing the RDATA to be created
  94. SSHFP::SSHFP(const string& sshfp_str) :
  95. impl_(NULL)
  96. {
  97. // We use auto_ptr here because if there is an exception in this
  98. // constructor, the destructor is not called and there could be a
  99. // leak of the SSHFPImpl that constructFromLexer() returns.
  100. std::auto_ptr<SSHFPImpl> impl_ptr(NULL);
  101. try {
  102. std::istringstream ss(sshfp_str);
  103. MasterLexer lexer;
  104. lexer.pushSource(ss);
  105. impl_ptr.reset(constructFromLexer(lexer));
  106. if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
  107. isc_throw(InvalidRdataText, "extra input text for SSHFP: "
  108. << sshfp_str);
  109. }
  110. } catch (const MasterLexer::LexerError& ex) {
  111. isc_throw(InvalidRdataText, "Failed to construct SSHFP from '" <<
  112. sshfp_str << "': " << ex.what());
  113. } catch (const isc::BadValue& e) {
  114. isc_throw(InvalidRdataText,
  115. "Bad SSHFP fingerprint: " << e.what());
  116. }
  117. impl_ = impl_ptr.release();
  118. }
  119. /// \brief Constructor with a context of MasterLexer.
  120. ///
  121. /// The \c lexer should point to the beginning of valid textual representation
  122. /// of an SSHFP RDATA.
  123. ///
  124. /// \throw MasterLexer::LexerError General parsing error such as missing field.
  125. /// \throw InvalidRdataText Fields are out of their valid range, or are
  126. /// incorrect.
  127. /// \throw BadValue Fingerprint is not a valid hex string.
  128. ///
  129. /// \param lexer A \c MasterLexer object parsing a master file for the
  130. /// RDATA to be created
  131. SSHFP::SSHFP(MasterLexer& lexer, const Name*,
  132. MasterLoader::Options, MasterLoaderCallbacks&) :
  133. impl_(constructFromLexer(lexer))
  134. {
  135. }
  136. /// \brief Constructor from InputBuffer.
  137. ///
  138. /// The passed buffer must contain a valid SSHFP RDATA.
  139. ///
  140. /// The Algorithm and Fingerprint Type fields are not checked for unknown
  141. /// values. It is okay for the fingerprint data to be missing (see the
  142. /// description of the constructor from string).
  143. SSHFP::SSHFP(InputBuffer& buffer, size_t rdata_len) {
  144. if (rdata_len < 2) {
  145. isc_throw(InvalidRdataLength, "SSHFP record too short");
  146. }
  147. const uint8_t algorithm = buffer.readUint8();
  148. const uint8_t fingerprint_type = buffer.readUint8();
  149. vector<uint8_t> fingerprint;
  150. rdata_len -= 2;
  151. if (rdata_len > 0) {
  152. fingerprint.resize(rdata_len);
  153. buffer.readData(&fingerprint[0], rdata_len);
  154. }
  155. impl_ = new SSHFPImpl(algorithm, fingerprint_type, fingerprint);
  156. }
  157. SSHFP::SSHFP(uint8_t algorithm, uint8_t fingerprint_type,
  158. const string& fingerprint_txt) :
  159. impl_(NULL)
  160. {
  161. vector<uint8_t> fingerprint;
  162. try {
  163. decodeHex(fingerprint_txt, fingerprint);
  164. } catch (const isc::BadValue& e) {
  165. isc_throw(InvalidRdataText, "Bad SSHFP fingerprint: " << e.what());
  166. }
  167. impl_ = new SSHFPImpl(algorithm, fingerprint_type, fingerprint);
  168. }
  169. SSHFP::SSHFP(const SSHFP& other) :
  170. Rdata(), impl_(new SSHFPImpl(*other.impl_))
  171. {}
  172. SSHFP&
  173. SSHFP::operator=(const SSHFP& source)
  174. {
  175. if (impl_ == source.impl_) {
  176. return (*this);
  177. }
  178. SSHFPImpl* newimpl = new SSHFPImpl(*source.impl_);
  179. delete impl_;
  180. impl_ = newimpl;
  181. return (*this);
  182. }
  183. SSHFP::~SSHFP() {
  184. delete impl_;
  185. }
  186. void
  187. SSHFP::toWire(OutputBuffer& buffer) const {
  188. buffer.writeUint8(impl_->algorithm_);
  189. buffer.writeUint8(impl_->fingerprint_type_);
  190. if (!impl_->fingerprint_.empty()) {
  191. buffer.writeData(&impl_->fingerprint_[0],
  192. impl_->fingerprint_.size());
  193. }
  194. }
  195. void
  196. SSHFP::toWire(AbstractMessageRenderer& renderer) const {
  197. renderer.writeUint8(impl_->algorithm_);
  198. renderer.writeUint8(impl_->fingerprint_type_);
  199. if (!impl_->fingerprint_.empty()) {
  200. renderer.writeData(&impl_->fingerprint_[0],
  201. impl_->fingerprint_.size());
  202. }
  203. }
  204. string
  205. SSHFP::toText() const {
  206. return (lexical_cast<string>(static_cast<int>(impl_->algorithm_)) + " " +
  207. lexical_cast<string>(static_cast<int>(impl_->fingerprint_type_)) +
  208. (impl_->fingerprint_.empty() ? "" :
  209. " " + encodeHex(impl_->fingerprint_)));
  210. }
  211. int
  212. SSHFP::compare(const Rdata& other) const {
  213. const SSHFP& other_sshfp = dynamic_cast<const SSHFP&>(other);
  214. if (impl_->algorithm_ < other_sshfp.impl_->algorithm_) {
  215. return (-1);
  216. } else if (impl_->algorithm_ > other_sshfp.impl_->algorithm_) {
  217. return (1);
  218. }
  219. if (impl_->fingerprint_type_ < other_sshfp.impl_->fingerprint_type_) {
  220. return (-1);
  221. } else if (impl_->fingerprint_type_ >
  222. other_sshfp.impl_->fingerprint_type_) {
  223. return (1);
  224. }
  225. const size_t this_len = impl_->fingerprint_.size();
  226. const size_t other_len = other_sshfp.impl_->fingerprint_.size();
  227. const size_t cmplen = min(this_len, other_len);
  228. if (cmplen > 0) {
  229. const int cmp = memcmp(&impl_->fingerprint_[0],
  230. &other_sshfp.impl_->fingerprint_[0],
  231. cmplen);
  232. if (cmp != 0) {
  233. return (cmp);
  234. }
  235. }
  236. if (this_len == other_len) {
  237. return (0);
  238. } else if (this_len < other_len) {
  239. return (-1);
  240. } else {
  241. return (1);
  242. }
  243. }
  244. uint8_t
  245. SSHFP::getAlgorithmNumber() const {
  246. return (impl_->algorithm_);
  247. }
  248. uint8_t
  249. SSHFP::getFingerprintType() const {
  250. return (impl_->fingerprint_type_);
  251. }
  252. size_t
  253. SSHFP::getFingerprintLen() const {
  254. return (impl_->fingerprint_.size());
  255. }
  256. // END_RDATA_NAMESPACE
  257. // END_ISC_NAMESPACE