// Copyright (C) 2010-2013 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace isc::util; using namespace isc::util::encode; using isc::dns::rdata::generic::detail::createNameFromLexer; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE namespace { // This is the minimum necessary length of all wire-format RRSIG RDATA: // - two 8-bit fields (algorithm and labels) // - two 16-bit fields (covered and tag) // - three 32-bit fields (original TTL, expire and inception) const size_t RRSIG_MINIMUM_LEN = 2 * sizeof(uint8_t) + 2 * sizeof(uint16_t) + 3 * sizeof(uint32_t); } struct RRSIGImpl { // straightforward representation of RRSIG RDATA fields RRSIGImpl(const RRType& covered, uint8_t algorithm, uint8_t labels, uint32_t originalttl, uint32_t timeexpire, uint32_t timeinception, uint16_t tag, const Name& signer, const vector& signature) : covered_(covered), algorithm_(algorithm), labels_(labels), originalttl_(originalttl), timeexpire_(timeexpire), timeinception_(timeinception), tag_(tag), signer_(signer), signature_(signature) {} const RRType covered_; uint8_t algorithm_; uint8_t labels_; uint32_t originalttl_; uint32_t timeexpire_; uint32_t timeinception_; uint16_t tag_; const Name signer_; const vector signature_; }; // helper function for string and lexer constructors void RRSIG::createFromLexer(MasterLexer& lexer, const Name* origin) { const string covered_txt = lexer.getNextToken(MasterToken::STRING).getString(); const uint32_t algorithm = lexer.getNextToken(MasterToken::NUMBER). getNumber(); const uint32_t labels = lexer.getNextToken(MasterToken::NUMBER). getNumber(); const uint32_t originalttl = RRTTL(lexer.getNextToken(MasterToken::STRING).getString()).getValue(); const string expire_txt = lexer.getNextToken(MasterToken::STRING).getString(); const string inception_txt = lexer.getNextToken(MasterToken::STRING).getString(); const uint32_t tag = lexer.getNextToken(MasterToken::NUMBER).getNumber(); const Name signer = createNameFromLexer(lexer, origin); const string signature_txt = lexer.getNextToken(MasterToken::STRING).getString(); if (algorithm > 0xff) { isc_throw(InvalidRdataText, "RRSIG algorithm out of range"); } if (labels > 0xff) { isc_throw(InvalidRdataText, "RRSIG labels out of range"); } if (tag > 0xffff) { isc_throw(InvalidRdataText, "RRSIG key tag out of range"); } const uint32_t timeexpire = timeFromText32(expire_txt); const uint32_t timeinception = timeFromText32(inception_txt); vector signature; decodeBase64(signature_txt, signature); impl_ = new RRSIGImpl(RRType(covered_txt), algorithm, labels, originalttl, timeexpire, timeinception, static_cast(tag), signer, signature); } /// \brief Constructor from string. /// /// The given string must represent a valid RRSIG RDATA. There can be extra /// space characters at the beginning or end of the text (which are simply /// ignored), but other extra text, including a new line, will make the /// construction fail with an exception. /// /// The Signer's Name must be absolute since there's no parameter that /// specifies the origin name; if this is not absolute, \c MissingNameOrigin /// exception will be thrown. This must not be represented as a quoted /// string. /// /// See the construction that takes \c MasterLexer for other fields. /// /// \throw Others Exception from the Name and RRTTL constructors. /// \throw InvalidRdataText Other general syntax errors. RRSIG::RRSIG(const std::string& rrsig_str) : impl_(NULL) { try { istringstream iss(rrsig_str); MasterLexer lexer; lexer.pushSource(iss); createFromLexer(lexer, NULL); if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { isc_throw(InvalidRdataText, "extra input text for RRSIG: " << rrsig_str); } } catch (const MasterLexer::LexerError& ex) { isc_throw(InvalidRdataText, "Failed to construct RRSIG from '" << rrsig_str << "': " << ex.what()); } } /// \brief Constructor with a context of MasterLexer. /// /// The \c lexer should point to the beginning of valid textual representation /// of an RRSIG RDATA. The Signer's Name fields can be non absolute if \c /// origin is non NULL, in which case \c origin is used to make it absolute. /// This must not be represented as a quoted string. /// /// The Original TTL field can be either a valid decimal representation of an /// unsigned 32-bit integer or other valid textual representation of \c RRTTL /// such as "1H" (which means 3600). /// /// \throw MasterLexer::LexerError General parsing error such as missing field. /// \throw Other Exceptions from the Name and RRTTL constructors if /// construction of textual fields as these objects fail. /// /// \param lexer A \c MasterLexer object parsing a master file for the /// RDATA to be created /// \param origin If non NULL, specifies the origin of Signer's Name when /// it is non absolute. RRSIG::RRSIG(MasterLexer& lexer, const Name* origin, MasterLoader::Options, MasterLoaderCallbacks&) : impl_(NULL) { createFromLexer(lexer, origin); } RRSIG::RRSIG(InputBuffer& buffer, size_t rdata_len) { size_t pos = buffer.getPosition(); if (rdata_len < RRSIG_MINIMUM_LEN) { isc_throw(InvalidRdataLength, "RRSIG too short"); } RRType covered(buffer); uint8_t algorithm = buffer.readUint8(); uint8_t labels = buffer.readUint8(); uint32_t originalttl = buffer.readUint32(); uint32_t timeexpire = buffer.readUint32(); uint32_t timeinception = buffer.readUint32(); uint16_t tag = buffer.readUint16(); Name signer(buffer); // rdata_len must be sufficiently large to hold non empty signature data. if (rdata_len <= buffer.getPosition() - pos) { isc_throw(InvalidRdataLength, "RRSIG too short"); } rdata_len -= (buffer.getPosition() - pos); vector signature(rdata_len); buffer.readData(&signature[0], rdata_len); impl_ = new RRSIGImpl(covered, algorithm, labels, originalttl, timeexpire, timeinception, tag, signer, signature); } RRSIG::RRSIG(const RRSIG& source) : Rdata(), impl_(new RRSIGImpl(*source.impl_)) {} RRSIG& RRSIG::operator=(const RRSIG& source) { if (impl_ == source.impl_) { return (*this); } RRSIGImpl* newimpl = new RRSIGImpl(*source.impl_); delete impl_; impl_ = newimpl; return (*this); } RRSIG::~RRSIG() { delete impl_; } string RRSIG::toText() const { return (impl_->covered_.toText() + " " + boost::lexical_cast(static_cast(impl_->algorithm_)) + " " + boost::lexical_cast(static_cast(impl_->labels_)) + " " + boost::lexical_cast(impl_->originalttl_) + " " + timeToText32(impl_->timeexpire_) + " " + timeToText32(impl_->timeinception_) + " " + boost::lexical_cast(impl_->tag_) + " " + impl_->signer_.toText() + " " + encodeBase64(impl_->signature_)); } void RRSIG::toWire(OutputBuffer& buffer) const { impl_->covered_.toWire(buffer); buffer.writeUint8(impl_->algorithm_); buffer.writeUint8(impl_->labels_); buffer.writeUint32(impl_->originalttl_); buffer.writeUint32(impl_->timeexpire_); buffer.writeUint32(impl_->timeinception_); buffer.writeUint16(impl_->tag_); impl_->signer_.toWire(buffer); buffer.writeData(&impl_->signature_[0], impl_->signature_.size()); } void RRSIG::toWire(AbstractMessageRenderer& renderer) const { impl_->covered_.toWire(renderer); renderer.writeUint8(impl_->algorithm_); renderer.writeUint8(impl_->labels_); renderer.writeUint32(impl_->originalttl_); renderer.writeUint32(impl_->timeexpire_); renderer.writeUint32(impl_->timeinception_); renderer.writeUint16(impl_->tag_); renderer.writeName(impl_->signer_, false); renderer.writeData(&impl_->signature_[0], impl_->signature_.size()); } int RRSIG::compare(const Rdata& other) const { const RRSIG& other_rrsig = dynamic_cast(other); if (impl_->covered_.getCode() != other_rrsig.impl_->covered_.getCode()) { return (impl_->covered_.getCode() < other_rrsig.impl_->covered_.getCode() ? -1 : 1); } if (impl_->algorithm_ != other_rrsig.impl_->algorithm_) { return (impl_->algorithm_ < other_rrsig.impl_->algorithm_ ? -1 : 1); } if (impl_->labels_ != other_rrsig.impl_->labels_) { return (impl_->labels_ < other_rrsig.impl_->labels_ ? -1 : 1); } if (impl_->originalttl_ != other_rrsig.impl_->originalttl_) { return (impl_->originalttl_ < other_rrsig.impl_->originalttl_ ? -1 : 1); } if (impl_->timeexpire_ != other_rrsig.impl_->timeexpire_) { return (impl_->timeexpire_ < other_rrsig.impl_->timeexpire_ ? -1 : 1); } if (impl_->timeinception_ != other_rrsig.impl_->timeinception_) { return (impl_->timeinception_ < other_rrsig.impl_->timeinception_ ? -1 : 1); } if (impl_->tag_ != other_rrsig.impl_->tag_) { return (impl_->tag_ < other_rrsig.impl_->tag_ ? -1 : 1); } int cmp = compareNames(impl_->signer_, other_rrsig.impl_->signer_); if (cmp != 0) { return (cmp); } size_t this_len = impl_->signature_.size(); size_t other_len = other_rrsig.impl_->signature_.size(); size_t cmplen = min(this_len, other_len); cmp = memcmp(&impl_->signature_[0], &other_rrsig.impl_->signature_[0], cmplen); if (cmp != 0) { return (cmp); } else { return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1); } } const RRType& RRSIG::typeCovered() const { return (impl_->covered_); } // END_RDATA_NAMESPACE // END_ISC_NAMESPACE