1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (C) 2021-2025 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/// @file gss_tsig_context.h Implements a TSIGContext derived class which
/// can be used as the value of TSIGContext pointers so with minimal or
/// update to the DNS++ library. The constructor takes a GSS-TSIG key
/// to share the associated GSS-API security context.

#ifndef GSS_TSIG_CONTEXT_H
#define GSS_TSIG_CONTEXT_H

#include <dns/tsig.h>
#include <gss_tsig_key.h>
#include <boost/shared_ptr.hpp>

namespace isc {
namespace gss_tsig {

/// @brief GSS-TSIG overwrite of the DNS TSIGContext class.
///
/// src/lib/dns/tsig.h includes a description of TSIGContext API.
///
/// The last TKEY response is signed but this is outside the state
/// transitions which are:
///
/// client side:
///   - INIT
///   - send a signed request
///   - SENT_REQUEST
///   - receive a signed response
///   - VERIFIED_RESPONSE
///
/// server side:
///   - INIT
///   - receive a signed request
///   - RECEIVED_REQUEST
///   - send a signed response
///
/// For TKEY on the reception of the last signed response:
///   - use the payload to finish the GSS-API security context establishment
///   - check the presence of a TSIG
///   - create a GssTsigContext object
///   - set its state to SENT_REQUEST
///   - verify the response using a pointer to the GssTsigContext object
///
/// For each exchange a different TSIGContext is required (no clear operation).
class GssTsigContext : public dns::TSIGContext {
public:
    /// @brief Constructor.
    ///
    /// @param key GSS-TSIG key.
    explicit GssTsigContext(GssTsigKey& key);

    /// @brief Destructor.
    virtual ~GssTsigContext();<--- Destructor in derived class

    /// @brief Sign a DNS message.
    ///
    /// See @c isc::dns::TSIGContext::sign().
    ///
    /// @param qid The QID to be as the value of the original ID field of
    /// the resulting TSIG record.
    /// @param data The wire-format data to be signed.
    /// @param data_len The length of @c data in bytes.
    /// @return A TSIG record for the given data along with the context.
    virtual dns::ConstTSIGRecordPtr
    sign(const uint16_t qid, const void* const data,
         const size_t data_len) override;

    /// @brief a DNS message.
    ///
    /// See @c isc::dns::TSIGContext::verify().
    ///
    virtual dns::TSIGError
    verify(const dns::TSIGRecord* const record, const void* const data,
           const size_t data_len) override;

    /// @brief Check whether the last verified message was signed.
    ///
    /// See @c isc::dns::TSIGContext::lastHadSignature().
    ///
    /// @return If the last message was signed or not.
    /// @exception TSIGContextError if no message was verified yet.
    virtual bool lastHadSignature() const override;

    /// @brief Return the expected length of TSIG RR after @c sign().
    ///
    /// See @c isc::dns::TSIGContext::getTSIGLength().
    ///
    /// @note: use the fixed constant of 128 from bind9.
    ///
    /// @return The expected TSIG RR length in bytes.
    virtual size_t getTSIGLength() const override;

    /// @brief Return the current state of the context.
    ///
    /// See @c isc::dns::TSIGContext::getState().
    ///
    /// @exception None.
    virtual State getState() const override {
        return (state_);
    }

    /// @brief Set the current state of the context.
    ///
    /// @note: to be used for the last TKEY response.
    ///
    /// @param state New state.
    virtual void setState(State state) {
        state_ = state;
    }

    /// @brief Return the TSIG error as a result of the latest verification.
    ///
    /// See @c isc::dns::TSIGContext::getError().
    ///
    /// @exception None.
    virtual dns::TSIGError getError() const override {
        return (error_);
    }

    /// @brief Set the TSIG error.
    ///
    /// @note: to be used for the last TKEY response.
    ///
    /// @param error New error.
    virtual void setError(dns::TSIGError error) {
        error_ = error;
    }

private:
    /// @brief State.
    State state_;

    /// @brief GSS-TSIG key.
    GssTsigKey& key_;

    /// @brief Previous digest.
    std::vector<uint8_t> previous_digest_;

    /// @brief TSIG error.
    dns::TSIGError error_;

    /// @brief Previous time signed.
    ///
    /// @note: only meaningful for response with BADTIME.
    uint64_t previous_timesigned_;

    /// @brief Distance from the last verified signed message.
    ///
    /// @note: Value of 0 means the last message was signed.
    /// Special value -1 means there was no signed message yet.
    int last_sig_dist_;

    /// @brief To be signed (or verified) buffer.
    util::OutputBuffer tbs_;

protected:
    /// @brief Update internal MAC 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.
    ///
    /// @param data Points to the wire-format data.
    /// @param len The length of @c data in bytes.
    void update(const void* const data, size_t len);<--- Derived function 'GssTsigContext::update'
};

/// @brief Type of pointer to a GSS-TSIG context.
typedef boost::shared_ptr<GssTsigContext> GssTsigContextPtr;

} // end of namespace isc::gss_tsig
} // end of namespace isc

#endif // GSS_TSIG_CONTEXT_H