Kea 2.7.6
|
TSIG session context. More...
#include <tsig.h>
Classes | |
struct | TSIGContextImpl |
Public Types | |
enum | State { INIT , SENT_REQUEST , RECEIVED_REQUEST , SENT_RESPONSE , VERIFIED_RESPONSE } |
Internal state of context. More... | |
Public Member Functions | |
Constructors and destructor | |
TSIGContext (const TSIGKey &key) | |
Constructor from a TSIG key. | |
TSIGContext (const Name &key_name, const Name &algorithm_name, const TSIGKeyRing &keyring) | |
Constructor from key parameters and key ring. | |
virtual | ~TSIGContext () |
The destructor. | |
virtual ConstTSIGRecordPtr | sign (const uint16_t qid, const void *const data, const size_t data_len) |
Sign a DNS message. | |
virtual TSIGError | verify (const TSIGRecord *const record, const void *const data, const size_t data_len) |
Verify a DNS message. | |
virtual bool | lastHadSignature () const |
Check whether the last verified message was signed. | |
virtual size_t | getTSIGLength () const |
Return the expected length of TSIG RR after sign() | |
virtual State | getState () const |
Return the current state of the context. | |
virtual TSIGError | getError () const |
Return the TSIG error as a result of the latest verification. | |
Protocol constants and defaults | |
static const uint16_t | DEFAULT_FUDGE = 300 |
The recommended fudge value (in seconds) by RFC2845. | |
void | update (const void *const data, size_t len) |
Update internal HMAC state by more data. | |
TSIG session context.
The TSIGContext
class maintains a context of a signed session of DNS transactions by TSIG. In many cases a TSIG signed session consists of a single set of request (e.g. normal query) and reply (e.g. normal response), where the request is initially signed by the client, and the reply is signed by the server using the initial signature. As mentioned in RFC2845, a session can consist of multiple exchanges in a TCP connection. As also mentioned in the RFC, an AXFR response often contains multiple DNS messages, which can belong to the same TSIG session. This class supports all these cases.
A TSIGContext
object is generally constructed with a TSIG key to be used for the session, and keeps track of various kinds of session specific information, such as the original digest while waiting for a response or verification error information that is to be used for a subsequent response.
This class has two main methods, sign()
and verify()
. The sign()
method signs given data (which is supposed to be a complete DNS message without the TSIG itself) using the TSIG key and other related information associated with the TSIGContext
object. The verify()
method verifies a given DNS message that contains a TSIG RR using the key and other internal information.
In general, a DNS client that wants to send a signed query will construct a TSIGContext
object with the TSIG key that the client is intending to use, and sign the query with the context. The client will keeps the context, and verify the response with it.
On the other hand, a DNS server will construct a TSIGContext
object with the information of the TSIG RR included in a query with a set of possible keys (in the form of a TSIGKeyRing
object). The constructor in this mode will identify the appropriate TSIG key (or internally record an error if it doesn't find a key). The server will then verify the query with the context, and generate a signed response using the same same context.
When multiple messages belong to the same TSIG session, either side (signer or verifier) will keep using the same context. It records the latest session state (such as the previous digest) so that repeated calls to sign()
or verify()
work correctly in terms of the TSIG protocol.
Examples
This is a typical client application that sends a TSIG signed query and verifies the response.
And this is a typical server application that authenticates a signed query and returns a response according to the result.
TCP Consideration
RFC2845 describes the case where a single TSIG session is used for multiple DNS messages (Section 4.4). This class supports signing and verifying the messages in this scenario, but does not care if the messages were delivered over a TCP connection or not. If, for example, the same TSIGContext
object is used to sign two independent DNS queries sent over UDP, they will be considered to belong to the same TSIG session, and, as a result, verification will be likely to fail.
Copyability
This class is currently non copyable based on the observation of the typical usage as described above. But there is no strong technical reason why this class cannot be copyable. If we see the need for it in future we may change the implementation on this point.
Note to developers: One basic design choice is to make the TSIGContext
class is as independent from the Message
class. This is because the latter is much more complicated, depending on many other classes, while TSIG is a very specific part of the entire DNS protocol set. If the TSIGContext
class depends on
it will be more vulnerable to changes to other classes, and will be more difficult to test due to the direct or indirect dependencies. The interface of Message
,sign()
that takes opaque data (instead of, e.g., a Message
or MessageRenderer
object) is therefore a deliberate design decision.
Internal state of context.
The constants of this enum type define a specific state of TSIGContext
to adjust the behavior. The definition is public and the state can be seen via the getState()
method, but this is mostly private information. It's publicly visible mainly for testing purposes; there is no API for the application to change the state directly.
|
explicit |
isc::dns::TSIGContext::TSIGContext | ( | const Name & | key_name, |
const Name & | algorithm_name, | ||
const TSIGKeyRing & | keyring ) |
Constructor from key parameters and key ring.
Definition at line 267 of file tsig.cc.
References isc::dns::TSIGError::BAD_KEY(), isc::dns::TSIGKeyRing::FindResult::code, isc::dns::TSIGKeyRing::find(), isc::dns::TSIGKeyRing::FindResult::key, and isc::dns::TSIGKeyRing::NOTFOUND.
|
virtual |
|
virtual |
|
virtual |
|
virtual |
Return the expected length of TSIG RR after sign()
This method returns the length of the TSIG RR that would be produced as a result of sign()
with the state of the context at the time of the call. The expected length can be decided from the key and the algorithm (which determines the MAC size if included) and the recorded TSIG error. Specifically, if a key related error has been identified, the MAC will be excluded; if a time error has occurred, the TSIG will include "other data".
This method is provided mainly for the convenience of the Message class, which needs to know the expected TSIG length in rendering a signed DNS message so that it can handle truncated messages with TSIG correctly. Normal applications wouldn't need this method. The Python binding for this method won't be provided for the same reason.
None |
Definition at line 287 of file tsig.cc.
References isc::dns::TSIGError::BAD_KEY(), isc::dns::TSIGError::BAD_SIG(), and isc::dns::TSIGError::BAD_TIME().
Referenced by isc::dns::MessageImpl::toWire().
|
virtual |
Check whether the last verified message was signed.
RFC2845 allows for some of the messages not to be signed. However, the last message must be signed and the class has no knowledge if a given message is the last one, therefore it can't check directly.
It is up to the caller to check if the last verified message was signed after all are verified by calling this function.
TSIGContextError | if no message was verified yet. |
Definition at line 558 of file tsig.cc.
References isc_throw.
|
virtual |
Sign a DNS message.
This method computes the TSIG MAC for the given data, which is generally expected to be a complete, wire-format DNS message that doesn't contain a TSIG RR, based on the TSIG key and other context information of TSIGContext
, and returns a result in the form of a (pointer object pointing to) TSIGRecord
object.
The caller of this method will use the returned value to render a complete TSIG RR into the message that has been signed so that it will become a complete TSIG-signed message.
In general, this method is called once by a client to send a signed request or one more times by a server to sign response(s) to a signed request. To avoid allowing accidental misuse, if this method is called after a "client" validates a response, an exception of class TSIGContextError
will be thrown.
Message::toWire()
method with a TSIGContext
object being a parameter and have the Message
class create a complete signed message.This method treats the given data as opaque, even though it's generally expected to represent a wire-format DNS message (see also the class description), and doesn't inspect it in any way. For example, it doesn't check whether the data length is sane for a valid DNS message. This is also the reason why this method takes the qid
parameter, which will be used as the original ID of the resulting TSIGRecordx
object, even though this value should be stored in the first two octets (in wire format) of the given data.
This method provides the strong exception guarantee; unless the method returns (without an exception being thrown), the internal state of the TSIGContext
won't be modified.
TSIGContextError | Context already verified a response. |
InvalidParameter | data is 0 or data_len is 0 |
cryptolink::LibraryError | Some unexpected error in the underlying crypto operation |
std::bad_alloc | Temporary resource allocation failure |
qid | The QID to be as the value of the original ID field of the resulting TSIG record |
data | Points to the wire-format data to be signed |
data_len | The length of data in bytes |
Definition at line 336 of file tsig.cc.
References isc::dns::TSIGError::BAD_KEY(), isc::dns::TSIGError::BAD_SIG(), isc::dns::TSIGError::BAD_TIME(), DEFAULT_FUDGE, isc::cryptolink::digest(), isc::dns::TSIGRecord::getClass(), isc::util::OutputBuffer::getData(), INIT, isc_throw, isc_throw_assert, isc::dns::TSIGError::NOERROR(), RECEIVED_REQUEST, SENT_REQUEST, SENT_RESPONSE, isc::dns::TSIGRecord::TSIG_TTL, VERIFIED_RESPONSE, isc::util::OutputBuffer::writeUint16(), and isc::util::OutputBuffer::writeUint32().
Referenced by isc::dns::MessageImpl::toWire().
|
protected |
Update internal HMAC state by more data.
This is used mostly internally, when we need to verify a message without TSIG signature in the middle of signed TCP stream. However, it is also used in tests, so it's protected instead of private, to allow tests in.
It doesn't contain sanity checks, and it is not tested directly. But we may want to add these one day to allow generating the skipped TSIG messages too. Until then, do not use this method.
Definition at line 566 of file tsig.cc.
Referenced by verify().
|
virtual |
Verify a DNS message.
This method verifies given data along with the context and a given TSIG in the form of a TSIGRecord
object. The data to be verified is generally expected to be a complete, wire-format DNS message, exactly as received by the host, and ending with a TSIG RR. After verification process this method updates its internal state, and returns the result in the form of a TSIGError
object. Possible return values are (see the TSIGError
class description for the mnemonics):
NOERROR:
The data has been verified correctly.FORMERR:
TSIGRecord
is not given (see below).BAD_KEY:
Appropriate key is not found or specified key doesn't match for the data.BAD_TIME:
The current time doesn't fall in the range specified in the TSIG.BAD_SIG:
The signature given in the TSIG doesn't match against the locally computed digest or is the signature is invalid in other way.BAD_MODE:
Not yet implemented TKEY errorBAD_NAME:
Not yet implemented TKEY errorBAD_ALG:
Not yet implemented TKEY errorBAD_TRUNC:
The signature or truncated signature length is too small.If this method is called by a DNS client waiting for a signed response and the result is not NOERROR
, the context can be used to try validating another signed message as described in RFC2845 Section 4.6.
If this method is called by a DNS server that tries to authenticate a signed request, and if the result is not NOERROR
, the corresponding error condition is recorded in the context so that the server can return a response indicating what was wrong by calling sign()
with the updated context.
In general, this method is called once by a server for authenticating a signed request or one more times by a client to validate signed response(s) to a signed request. To avoid allowing accidental misuse, if this method is called after a "server" signs a response, an exception of class TSIGContextError
will be thrown.
The record
parameter can be 0; in that case this method simply returns FORMERR
as the case described in Section 4.6 of RFC2845, i.e., receiving an unsigned response to a signed request. This way a client can transparently pass the result of Message::getTSIGRecord()
without checking whether it isn't 0 and take an appropriate action based on the result of this method.
This method handles the given data mostly as opaque. It digests the data assuming it begins with a DNS header and ends with a TSIG RR whose length is given by calling TSIGRecord::getLength()
on record
, but otherwise it doesn't parse the data to confirm the assumption. It's caller's responsibility to ensure the data is valid and consistent with record
. To avoid disruption, this method performs minimal validation on the given data
and record:
data
must not be 0; data_len
must not be smaller than the sum of the DNS header length (fixed, 12 octets) and the length of the TSIG RR. If this check fails it throws an InvalidParameter
exception.
One unexpected case that is not covered by this method is that a client receives a signed response to an unsigned request. RFC2845 is silent about such cases; BIND 9 explicitly identifies the case and rejects it. With this implementation, the client can know that the response contains a TSIG via the result of Message::getTSIGRecord()
and that it is an unexpected TSIG due to the fact that it doesn't have a corresponding TSIGContext
. It's up to the client implementation whether to react to such a case explicitly (for example, it could either ignore the TSIG and accept the response or drop it).
This method provides the strong exception guarantee; unless the method returns (without an exception being thrown), the internal state of the TSIGContext
won't be modified.
TSIGContextError | Context already signed a response. |
InvalidParameter | data is 0 or data_len is too small. |
record | The TSIGRecord to be verified with data |
data | Points to the wire-format data (exactly as received) to be verified |
data_len | The length of data in bytes |
TSIGError
that indicates verification result Definition at line 419 of file tsig.cc.
References isc::dns::TSIGError::BAD_KEY(), isc::dns::TSIGError::BAD_SIG(), isc::dns::TSIGError::BAD_TIME(), isc::dns::TSIGError::BAD_TRUNC(), DEFAULT_FUDGE, isc::cryptolink::digest(), isc::dns::TSIGError::FORMERR(), isc::dns::rdata::any::TSIG::getAlgorithm(), isc::dns::TSIGRecord::getClass(), isc::dns::rdata::any::TSIG::getError(), isc::dns::rdata::any::TSIG::getFudge(), isc::dns::TSIGRecord::getLength(), isc::dns::rdata::any::TSIG::getMAC(), isc::dns::rdata::any::TSIG::getMACSize(), isc::dns::TSIGRecord::getName(), isc::dns::rdata::any::TSIG::getOriginalID(), isc::dns::rdata::any::TSIG::getOtherData(), isc::dns::rdata::any::TSIG::getOtherLen(), isc::dns::TSIGRecord::getRdata(), isc::dns::rdata::any::TSIG::getTimeSigned(), INIT, isc_throw, isc::dns::TSIGError::NOERROR(), SENT_RESPONSE, isc::dns::TSIGRecord::TSIG_TTL, update(), and VERIFIED_RESPONSE.
Referenced by isc::d2::D2UpdateMessage::fromWire().
|
static |