tsig.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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. #ifndef __TSIG_H
  15. #define __TSIG_H 1
  16. #include <boost/noncopyable.hpp>
  17. #include <exceptions/exceptions.h>
  18. #include <dns/tsigerror.h>
  19. #include <dns/tsigkey.h>
  20. #include <dns/tsigrecord.h>
  21. namespace isc {
  22. namespace dns {
  23. /// An exception that is thrown for logic errors identified in TSIG
  24. /// sign/verify operations.
  25. ///
  26. /// Note that this exception is not thrown for TSIG protocol errors such as
  27. /// verification failures. In general, this exception indicates an internal
  28. /// program bug.
  29. class TSIGContextError : public isc::Exception {
  30. public:
  31. TSIGContextError(const char* file, size_t line, const char* what) :
  32. isc::Exception(file, line, what) {}
  33. };
  34. /// TSIG session context.
  35. ///
  36. /// The \c TSIGContext class maintains a context of a signed session of
  37. /// DNS transactions by TSIG. In many cases a TSIG signed session consists
  38. /// of a single set of request (e.g. normal query) and reply (e.g. normal
  39. /// response), where the request is initially signed by the client, and the
  40. /// reply is signed by the server using the initial signature. As mentioned
  41. /// in RFC2845, a session can consist of multiple exchanges in a TCP
  42. /// connection. As also mentioned in the RFC, an AXFR response often contains
  43. /// multiple DNS messages, which can belong to the same TSIG session.
  44. /// This class supports all these cases.
  45. ///
  46. /// A \c TSIGContext object is generally constructed with a TSIG key to be
  47. /// used for the session, and keeps track of various kinds of session specific
  48. /// information, such as the original digest while waiting for a response or
  49. /// verification error information that is to be used for a subsequent
  50. /// response.
  51. ///
  52. /// This class has two main methods, \c sign() and \c verify().
  53. /// The \c sign() method signs given data (which is supposed to be a complete
  54. /// DNS message without the TSIG itself) using the TSIG key and other
  55. /// related information associated with the \c TSIGContext object.
  56. /// The \c verify() method verifies a given DNS message that contains a TSIG
  57. /// RR using the key and other internal information.
  58. ///
  59. /// In general, a DNS client that wants to send a signed query will construct
  60. /// a \c TSIGContext object with the TSIG key that the client is intending to
  61. /// use, and sign the query with the context. The client will keeps the
  62. /// context, and verify the response with it.
  63. ///
  64. /// On the other hand, a DNS server will construct a \c TSIGContext object
  65. /// with the information of the TSIG RR included in a query with a set of
  66. /// possible keys (in the form of a \c TSIGKeyRing object). The constructor
  67. /// in this mode will identify the appropriate TSIG key (or internally record
  68. /// an error if it doesn't find a key). The server will then verify the
  69. /// query with the context, and generate a signed response using the same
  70. /// same context.
  71. ///
  72. /// When multiple messages belong to the same TSIG session, either side
  73. /// (signer or verifier) will keep using the same context. It records
  74. /// the latest session state (such as the previous digest) so that repeated
  75. /// calls to \c sign() or \c verify() work correctly in terms of the TSIG
  76. /// protocol.
  77. ///
  78. /// \b Examples
  79. ///
  80. /// This is a typical client application that sends a TSIG signed query
  81. /// and verifies the response.
  82. ///
  83. /// \code
  84. /// // "renderer" is of MessageRenderer to render the message.
  85. /// // (TSIGKey would be configured from config or command line in real app)
  86. /// TSIGContext ctx(TSIGKey("key.example:MSG6Ng=="));
  87. /// Message message(Message::RENDER);
  88. /// message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
  89. /// RRType::A()));
  90. /// message.toWire(renderer, ctx);
  91. ///
  92. /// // sendto, then recvfrom. received result in (data, data_len)
  93. ///
  94. /// message.clear(Message::PARSE);
  95. /// InputBuffer buffer(data, data_len);
  96. /// message.fromWire(buffer);
  97. /// TSIGError tsig_error = ctx.verify(message.getTSIGRecord(),
  98. /// data, data_len);
  99. /// if (tsig_error == TSIGError::NOERROR()) {
  100. /// // okay. ctx can be continuously used if it's receiving subsequent
  101. /// // signed responses from a TCP stream.
  102. /// } else if (message.getRcode() == Rcode::NOTAUTH()) {
  103. /// // hard error. give up this transaction per RFC2845 4.6.
  104. /// } else {
  105. /// // Other error: discard response keep waiting with the same ctx
  106. /// // for another (again, RFC2845 4.6).
  107. /// } \endcode
  108. ///
  109. /// And this is a typical server application that authenticates a signed
  110. /// query and returns a response according to the result.
  111. ///
  112. /// \code
  113. /// // Assume "message" is of type Message for query handling and
  114. /// // "renderer" is of MessageRenderer to render responses.
  115. /// Message message(Message::RENDER);
  116. ///
  117. /// TSIGKeyRing keyring; // this must be configured with keys somewhere
  118. ///
  119. /// // Receive a query and store it in (data, data_len)
  120. /// InputBuffer buffer(data, data_len);
  121. /// message.clear(Message::PARSE);
  122. /// message.fromWire(buffer);
  123. ///
  124. /// const TSIGRecord* tsig = message.getTSIGRecord();
  125. /// if (tsig != NULL) {
  126. /// TSIGContext ctx(tsig->getName(), tsig->getRdata().getAlgorithm(),
  127. /// keyring);
  128. /// ctx.verify(tsig, data, data_len);
  129. ///
  130. /// // prepare response
  131. /// message.makeResponse();
  132. /// //...
  133. /// message.toWire(renderer, ctx);
  134. ///
  135. /// // send the response data back to the client.
  136. /// // If this is a beginning of a signed session over a TCP and
  137. /// // server has more data to send to the client, this ctx
  138. /// // will be used to sign subsequent messages.
  139. /// } \endcode
  140. ///
  141. /// <b>TCP Consideration</b>
  142. ///
  143. /// RFC2845 describes the case where a single TSIG session is used for
  144. /// multiple DNS messages (Section 4.4). This class supports signing and
  145. /// verifying the messages in this scenario, but does not care if the messages
  146. /// were delivered over a TCP connection or not. If, for example, the
  147. /// same \c TSIGContext object is used to sign two independent DNS queries
  148. /// sent over UDP, they will be considered to belong to the same TSIG
  149. /// session, and, as a result, verification will be likely to fail.
  150. ///
  151. /// \b Copyability
  152. ///
  153. /// This class is currently non copyable based on the observation of the
  154. /// typical usage as described above. But there is no strong technical
  155. /// reason why this class cannot be copyable. If we see the need for it
  156. /// in future we may change the implementation on this point.
  157. ///
  158. /// <b>Note to developers:</b>
  159. /// One basic design choice is to make the \c TSIGContext class is as
  160. /// independent from the \c Message class. This is because the latter is
  161. /// much more complicated, depending on many other classes, while TSIG is
  162. /// a very specific part of the entire DNS protocol set. If the \c TSIGContext
  163. /// class depends on \c \c Message, it will be more vulnerable to changes
  164. /// to other classes, and will be more difficult to test due to the
  165. /// direct or indirect dependencies. The interface of \c sign() that takes
  166. /// opaque data (instead of, e.g., a \c Message or \c MessageRenderer object)
  167. /// is therefore a deliberate design decision.
  168. class TSIGContext : boost::noncopyable {
  169. public:
  170. /// Internal state of context
  171. ///
  172. /// The constants of this enum type define a specific state of
  173. /// \c TSIGContext to adjust the behavior. The definition is public
  174. /// and the state can be seen via the \c getState() method, but this is
  175. /// mostly private information. It's publicly visible mainly for testing
  176. /// purposes; there is no API for the application to change the state
  177. /// directly.
  178. enum State {
  179. INIT, ///< Initial state
  180. SENT_REQUEST, ///< Client sent a signed request, waiting response
  181. RECEIVED_REQUEST, ///< Server received a signed request
  182. SENT_RESPONSE, ///< Server sent a signed response
  183. VERIFIED_RESPONSE ///< Client successfully verified a response
  184. };
  185. /// \name Constructors and destructor
  186. ///
  187. //@{
  188. /// Constructor from a TSIG key.
  189. ///
  190. /// \exception std::bad_alloc Resource allocation for internal data fails
  191. ///
  192. /// \param key The TSIG key to be used for TSIG sessions with this context.
  193. explicit TSIGContext(const TSIGKey& key);
  194. /// Constructor from key parameters and key ring.
  195. TSIGContext(const Name& key_name, const Name& algorithm_name,
  196. const TSIGKeyRing& keyring);
  197. /// The destructor.
  198. ~TSIGContext();
  199. //@}
  200. /// Sign a DNS message.
  201. ///
  202. /// This method computes the TSIG MAC for the given data, which is
  203. /// generally expected to be a complete, wire-format DNS message
  204. /// that doesn't contain a TSIG RR, based on the TSIG key and
  205. /// other context information of \c TSIGContext, and returns a
  206. /// result in the form of a (pointer object pointing to)
  207. /// \c TSIGRecord object.
  208. ///
  209. /// The caller of this method will use the returned value to render a
  210. /// complete TSIG RR into the message that has been signed so that it
  211. /// will become a complete TSIG-signed message.
  212. ///
  213. /// In general, this method is called once by a client to send a
  214. /// signed request or one more times by a server to sign
  215. /// response(s) to a signed request. To avoid allowing accidental
  216. /// misuse, if this method is called after a "client" validates a
  217. /// response, an exception of class \c TSIGContextError will be
  218. /// thrown.
  219. ///
  220. /// \note Normal applications are not expected to call this method
  221. /// directly; they will usually use the \c Message::toWire() method
  222. /// with a \c TSIGContext object being a parameter and have the
  223. /// \c Message class create a complete signed message.
  224. ///
  225. /// This method treats the given data as opaque, even though it's generally
  226. /// expected to represent a wire-format DNS message (see also the class
  227. /// description), and doesn't inspect it in any way. For example, it
  228. /// doesn't check whether the data length is sane for a valid DNS message.
  229. /// This is also the reason why this method takes the \c qid parameter,
  230. /// which will be used as the original ID of the resulting
  231. /// \c TSIGRecordx object, even though this value should be stored in the
  232. /// first two octets (in wire format) of the given data.
  233. ///
  234. /// \note This method still checks and rejects empty data (\c NULL pointer
  235. /// data or the specified data length is 0) in order to avoid catastrophic
  236. /// effect such as program crash. Empty data is not necessarily invalid
  237. /// for HMAC computation, but obviously it doesn't make sense for a DNS
  238. /// message.
  239. ///
  240. /// This method provides the strong exception guarantee; unless the method
  241. /// returns (without an exception being thrown), the internal state of
  242. /// the \c TSIGContext won't be modified.
  243. ///
  244. /// \exception TSIGContextError Context already verified a response.
  245. /// \exception InvalidParameter \c data is NULL or \c data_len is 0
  246. /// \exception cryptolink::LibraryError Some unexpected error in the
  247. /// underlying crypto operation
  248. /// \exception std::bad_alloc Temporary resource allocation failure
  249. ///
  250. /// \param qid The QID to be as the value of the original ID field of
  251. /// the resulting TSIG record
  252. /// \param data Points to the wire-format data to be signed
  253. /// \param data_len The length of \c data in bytes
  254. ///
  255. /// \return A TSIG record for the given data along with the context.
  256. ConstTSIGRecordPtr sign(const uint16_t qid, const void* const data,
  257. const size_t data_len);
  258. /// Verify a DNS message.
  259. ///
  260. /// This method verifies given data along with the context and a given
  261. /// TSIG in the form of a \c TSIGRecord object. The data to be verified
  262. /// is generally expected to be a complete, wire-format DNS message,
  263. /// exactly as received by the host, and ending with a TSIG RR.
  264. /// After verification process this method updates its internal state,
  265. /// and returns the result in the form of a \c TSIGError object.
  266. /// Possible return values are (see the \c TSIGError class description
  267. /// for the mnemonics):
  268. ///
  269. /// - \c NOERROR: The data has been verified correctly.
  270. /// - \c FORMERR: \c TSIGRecord is not given (see below).
  271. /// - \c BAD_KEY: Appropriate key is not found or specified key doesn't
  272. /// match for the data.
  273. /// - \c BAD_TIME: The current time doesn't fall in the range specified
  274. /// in the TSIG.
  275. /// - \c BAD_SIG: The signature given in the TSIG doesn't match against
  276. /// the locally computed digest or is the signature is
  277. /// invalid in other way.
  278. ///
  279. /// If this method is called by a DNS client waiting for a signed
  280. /// response and the result is not \c NOERROR, the context can be used
  281. /// to try validating another signed message as described in RFC2845
  282. /// Section 4.6.
  283. ///
  284. /// If this method is called by a DNS server that tries to authenticate
  285. /// a signed request, and if the result is not \c NOERROR, the
  286. /// corresponding error condition is recorded in the context so that
  287. /// the server can return a response indicating what was wrong by calling
  288. /// \c sign() with the updated context.
  289. ///
  290. /// In general, this method is called once by a server for
  291. /// authenticating a signed request or one more times by a client to
  292. /// validate signed response(s) to a signed request. To avoid allowing
  293. /// accidental misuse, if this method is called after a "server" signs
  294. /// a response, an exception of class \c TSIGContextError will be thrown.
  295. ///
  296. /// The \c record parameter can be NULL; in that case this method simply
  297. /// returns \c FORMERR as the case described in Section 4.6 of RFC2845,
  298. /// i.e., receiving an unsigned response to a signed request. This way
  299. /// a client can transparently pass the result of
  300. /// \c Message::getTSIGRecord() without checking whether it's non NULL
  301. /// and take an appropriate action based on the result of this method.
  302. ///
  303. /// This method handles the given data mostly as opaque. It digests
  304. /// the data assuming it begins with a DNS header and ends with a TSIG
  305. /// RR whose length is given by calling \c TSIGRecord::getLength() on
  306. /// \c record, but otherwise it doesn't parse the data to confirm the
  307. /// assumption. It's caller's responsibility to ensure the data is
  308. /// valid and consistent with \c record. To avoid disruption, this
  309. /// method performs minimal validation on the given \c data and \c record:
  310. /// \c data must not be NULL; \c data_len must not be smaller than the
  311. /// sum of the DNS header length (fixed, 12 octets) and the length of
  312. /// the TSIG RR. If this check fails it throws an \c InvalidParameter
  313. /// exception.
  314. ///
  315. /// One unexpected case that is not covered by this method is that a
  316. /// client receives a signed response to an unsigned request. RFC2845 is
  317. /// silent about such cases; BIND 9 explicitly identifies the case and
  318. /// rejects it. With this implementation, the client can know that the
  319. /// response contains a TSIG via the result of
  320. /// \c Message::getTSIGRecord() and that it is an unexpected TSIG due to
  321. /// the fact that it doesn't have a corresponding \c TSIGContext.
  322. /// It's up to the client implementation whether to react to such a case
  323. /// explicitly (for example, it could either ignore the TSIG and accept
  324. /// the response or drop it).
  325. ///
  326. /// This method provides the strong exception guarantee; unless the method
  327. /// returns (without an exception being thrown), the internal state of
  328. /// the \c TSIGContext won't be modified.
  329. ///
  330. /// \todo Support intermediate TCP DNS messages without TSIG (RFC2845 4.4)
  331. /// \todo Signature truncation support based on RFC4635
  332. ///
  333. /// \exception TSIGContextError Context already signed a response.
  334. /// \exception InvalidParameter \c data is NULL or \c data_len is too small.
  335. ///
  336. /// \param record The \c TSIGRecord to be verified with \c data
  337. /// \param data Points to the wire-format data (exactly as received) to
  338. /// be verified
  339. /// \param data_len The length of \c data in bytes
  340. /// \return The \c TSIGError that indicates verification result
  341. TSIGError verify(const TSIGRecord* const record, const void* const data,
  342. const size_t data_len);
  343. /// Return the current state of the context
  344. ///
  345. /// \note
  346. /// The states are visible in public mainly for testing purposes.
  347. /// Normal applications won't have to deal with them.
  348. ///
  349. /// \exception None
  350. State getState() const;
  351. /// Return the TSIG error as a result of the latest verification
  352. ///
  353. /// This method can be called even before verifying anything, but the
  354. /// returned value is meaningless in that case.
  355. ///
  356. /// \exception None
  357. TSIGError getError() const;
  358. /// \name Protocol constants and defaults
  359. ///
  360. //@{
  361. /// The recommended fudge value (in seconds) by RFC2845.
  362. ///
  363. /// Right now fudge is not tunable, and all TSIGs generated by this API
  364. /// will have this value of fudge.
  365. static const uint16_t DEFAULT_FUDGE = 300;
  366. //@}
  367. private:
  368. struct TSIGContextImpl;
  369. TSIGContextImpl* impl_;
  370. };
  371. }
  372. }
  373. #endif // __TSIG_H
  374. // Local Variables:
  375. // mode: c++
  376. // End: