mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
[1136] Implement the SSHFP type, from RFC 4255
This commit is contained in:
164
src/lib/dns/rdata/generic/sshfp_44.cc
Normal file
164
src/lib/dns/rdata/generic/sshfp_44.cc
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright (C) 2012 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 <config.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
#include <util/buffer.h>
|
||||
#include <util/encode/hex.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/messagerenderer.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdataclass.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
using namespace isc::util;
|
||||
using namespace isc::util::encode;
|
||||
|
||||
// BEGIN_ISC_NAMESPACE
|
||||
// BEGIN_RDATA_NAMESPACE
|
||||
|
||||
SSHFP::SSHFP(InputBuffer& buffer, size_t rdata_len)
|
||||
{
|
||||
if (rdata_len < 2) {
|
||||
isc_throw(InvalidRdataLength, "SSHFP record too short");
|
||||
}
|
||||
|
||||
algorithm_ = buffer.readUint8();
|
||||
fingerprint_type_ = buffer.readUint8();
|
||||
|
||||
rdata_len -= 2;
|
||||
fingerprint_.resize(rdata_len);
|
||||
buffer.readData(&fingerprint_[0], rdata_len);
|
||||
}
|
||||
|
||||
SSHFP::SSHFP(const std::string& sshfp_str)
|
||||
{
|
||||
std::istringstream iss(sshfp_str);
|
||||
// peekc should be of iss's char_type for isspace to work
|
||||
std::istringstream::char_type peekc;
|
||||
std::stringbuf fingerprintbuf;
|
||||
uint32_t algorithm, fingerprint_type;
|
||||
|
||||
iss >> algorithm >> fingerprint_type;
|
||||
if (iss.bad() || iss.fail()) {
|
||||
isc_throw(InvalidRdataText, "Invalid SSHFP text");
|
||||
}
|
||||
if ((algorithm < 1) || (algorithm > 2)) {
|
||||
isc_throw(InvalidRdataText, "SSHFP algorithm number out of range");
|
||||
}
|
||||
if (fingerprint_type != 1) {
|
||||
isc_throw(InvalidRdataText, "SSHFP fingerprint type out of range");
|
||||
}
|
||||
|
||||
iss.read(&peekc, 1);
|
||||
if (!iss.good() || !isspace(peekc, iss.getloc())) {
|
||||
isc_throw(InvalidRdataText, "SSHFP presentation format error");
|
||||
}
|
||||
|
||||
iss >> &fingerprintbuf;
|
||||
|
||||
algorithm_ = algorithm;
|
||||
fingerprint_type_ = fingerprint_type;
|
||||
decodeHex(fingerprintbuf.str(), fingerprint_);
|
||||
}
|
||||
|
||||
SSHFP::SSHFP(uint8_t algorithm, uint8_t fingerprint_type, const string& fingerprint)
|
||||
{
|
||||
if ((algorithm < 1) || (algorithm > 2)) {
|
||||
isc_throw(InvalidRdataText, "SSHFP algorithm number out of range");
|
||||
}
|
||||
if (fingerprint_type != 1) {
|
||||
isc_throw(InvalidRdataText, "SSHFP fingerprint type out of range");
|
||||
}
|
||||
|
||||
algorithm_ = algorithm;
|
||||
fingerprint_type_ = fingerprint_type;
|
||||
decodeHex(fingerprint, fingerprint_);
|
||||
}
|
||||
|
||||
SSHFP::SSHFP(const SSHFP& other) :
|
||||
Rdata(), algorithm_(other.algorithm_), fingerprint_type_(other.fingerprint_type_), fingerprint_(other.fingerprint_)
|
||||
{}
|
||||
|
||||
void
|
||||
SSHFP::toWire(OutputBuffer& buffer) const {
|
||||
buffer.writeUint8(algorithm_);
|
||||
buffer.writeUint8(fingerprint_type_);
|
||||
buffer.writeData(&fingerprint_[0], fingerprint_.size());
|
||||
}
|
||||
|
||||
void
|
||||
SSHFP::toWire(AbstractMessageRenderer& renderer) const {
|
||||
renderer.writeUint8(algorithm_);
|
||||
renderer.writeUint8(fingerprint_type_);
|
||||
renderer.writeData(&fingerprint_[0], fingerprint_.size());
|
||||
}
|
||||
|
||||
string
|
||||
SSHFP::toText() const {
|
||||
return (lexical_cast<string>(static_cast<int>(algorithm_)) +
|
||||
" " + lexical_cast<string>(static_cast<int>(fingerprint_type_)) +
|
||||
" " + encodeHex(fingerprint_));
|
||||
}
|
||||
|
||||
int
|
||||
SSHFP::compare(const Rdata& other) const {
|
||||
const SSHFP& other_sshfp = dynamic_cast<const SSHFP&>(other);
|
||||
|
||||
/* This doesn't really make any sort of sense, but in the name of
|
||||
consistency... */
|
||||
|
||||
if (algorithm_ < other_sshfp.algorithm_) {
|
||||
return (-1);
|
||||
} else if (algorithm_ > other_sshfp.algorithm_) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (fingerprint_type_ < other_sshfp.fingerprint_type_) {
|
||||
return (-1);
|
||||
} else if (fingerprint_type_ > other_sshfp.fingerprint_type_) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
size_t this_len = fingerprint_.size();
|
||||
size_t other_len = other_sshfp.fingerprint_.size();
|
||||
size_t cmplen = min(this_len, other_len);
|
||||
int cmp = memcmp(&fingerprint_[0], &other_sshfp.fingerprint_[0], cmplen);
|
||||
if (cmp != 0) {
|
||||
return (cmp);
|
||||
} else {
|
||||
return ((this_len == other_len)
|
||||
? 0 : (this_len < other_len) ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t
|
||||
SSHFP::getSSHFPAlgorithmNumber() const {
|
||||
return (algorithm_);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
SSHFP::getSSHFPFingerprintType() const {
|
||||
return (fingerprint_type_);
|
||||
}
|
||||
|
||||
// END_RDATA_NAMESPACE
|
||||
// END_ISC_NAMESPACE
|
58
src/lib/dns/rdata/generic/sshfp_44.h
Normal file
58
src/lib/dns/rdata/generic/sshfp_44.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// BEGIN_HEADER_GUARD
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <dns/name.h>
|
||||
#include <dns/rdata.h>
|
||||
|
||||
// BEGIN_ISC_NAMESPACE
|
||||
|
||||
// BEGIN_COMMON_DECLARATIONS
|
||||
// END_COMMON_DECLARATIONS
|
||||
|
||||
// BEGIN_RDATA_NAMESPACE
|
||||
|
||||
class SSHFP : public Rdata {
|
||||
public:
|
||||
// BEGIN_COMMON_MEMBERS
|
||||
// END_COMMON_MEMBERS
|
||||
|
||||
SSHFP(uint8_t algorithm, uint8_t fingerprint_type, const std::string& fingerprint);
|
||||
|
||||
///
|
||||
/// Specialized methods
|
||||
///
|
||||
uint8_t getSSHFPAlgorithmNumber() const;
|
||||
uint8_t getSSHFPFingerprintType() const;
|
||||
|
||||
private:
|
||||
/// Note: this is a prototype version; we may reconsider
|
||||
/// this representation later.
|
||||
uint8_t algorithm_;
|
||||
uint8_t fingerprint_type_;
|
||||
std::vector<uint8_t> fingerprint_;
|
||||
};
|
||||
|
||||
// END_RDATA_NAMESPACE
|
||||
// END_ISC_NAMESPACE
|
||||
// END_HEADER_GUARD
|
||||
|
||||
// Local Variables:
|
||||
// mode: c++
|
||||
// End:
|
@@ -33,6 +33,7 @@ run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc
|
||||
run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
|
||||
run_unittests_SOURCES += rdata_txt_like_unittest.cc
|
||||
run_unittests_SOURCES += rdata_mx_unittest.cc
|
||||
run_unittests_SOURCES += rdata_sshfp_unittest.cc
|
||||
run_unittests_SOURCES += rdata_ptr_unittest.cc rdata_cname_unittest.cc
|
||||
run_unittests_SOURCES += rdata_dname_unittest.cc
|
||||
run_unittests_SOURCES += rdata_afsdb_unittest.cc
|
||||
|
79
src/lib/dns/tests/rdata_sshfp_unittest.cc
Normal file
79
src/lib/dns/tests/rdata_sshfp_unittest.cc
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright (C) 2012 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 <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <util/buffer.h>
|
||||
#include <dns/messagerenderer.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdataclass.h>
|
||||
#include <dns/rrclass.h>
|
||||
#include <dns/rrtype.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <dns/tests/unittest_util.h>
|
||||
#include <dns/tests/rdata_unittest.h>
|
||||
|
||||
using isc::UnitTestUtil;
|
||||
using namespace std;
|
||||
using namespace isc::dns;
|
||||
using namespace isc::util;
|
||||
using namespace isc::dns::rdata;
|
||||
|
||||
namespace {
|
||||
class Rdata_SSHFP_Test : public RdataTest {
|
||||
// there's nothing to specialize
|
||||
};
|
||||
|
||||
const string sshfp_txt("2 1 123456789abcdef67890123456789abcdef67890");
|
||||
const generic::SSHFP rdata_sshfp(2, 1, "123456789abcdef67890123456789abcdef67890");
|
||||
|
||||
TEST_F(Rdata_SSHFP_Test, createFromText) {
|
||||
const generic::SSHFP rdata_sshfp2(sshfp_txt);
|
||||
EXPECT_EQ(0, rdata_sshfp2.compare(rdata_sshfp));
|
||||
}
|
||||
|
||||
TEST_F(Rdata_SSHFP_Test, badText) {
|
||||
EXPECT_THROW(const generic::SSHFP rdata_sshfp("1"), InvalidRdataText);
|
||||
EXPECT_THROW(const generic::SSHFP rdata_sshfp("1 2"), InvalidRdataText);
|
||||
EXPECT_THROW(const generic::SSHFP rdata_sshfp("BUCKLE MY SHOES"), InvalidRdataText);
|
||||
EXPECT_THROW(const generic::SSHFP rdata_sshfp("1 2 foo bar"), InvalidRdataText);
|
||||
}
|
||||
|
||||
TEST_F(Rdata_SSHFP_Test, copy) {
|
||||
const generic::SSHFP rdata_sshfp2(rdata_sshfp);
|
||||
EXPECT_EQ(0, rdata_sshfp.compare(rdata_sshfp2));
|
||||
}
|
||||
|
||||
TEST_F(Rdata_SSHFP_Test, createFromWire) {
|
||||
EXPECT_EQ(0, rdata_sshfp.compare(
|
||||
*rdataFactoryFromFile(RRType("SSHFP"), RRClass("IN"),
|
||||
"rdata_sshfp_fromWire.wire")));
|
||||
// TBD: more tests
|
||||
}
|
||||
|
||||
TEST_F(Rdata_SSHFP_Test, toText) {
|
||||
EXPECT_EQ("2 1 123456789abcdef67890123456789abcdef67890", rdata_sshfp.toText());
|
||||
}
|
||||
|
||||
TEST_F(Rdata_SSHFP_Test, getSSHFPAlgorithmNumber) {
|
||||
EXPECT_EQ(2, rdata_sshfp.getSSHFPAlgorithmNumber());
|
||||
}
|
||||
|
||||
TEST_F(Rdata_SSHFP_Test, getSSHFPFingerprintType) {
|
||||
EXPECT_EQ(1, rdata_sshfp.getSSHFPFingerprintType());
|
||||
}
|
||||
}
|
2
src/lib/dns/tests/testdata/Makefile.am
vendored
2
src/lib/dns/tests/testdata/Makefile.am
vendored
@@ -44,6 +44,7 @@ BUILT_SOURCES += rdata_rp_fromWire1.wire rdata_rp_fromWire2.wire
|
||||
BUILT_SOURCES += rdata_rp_fromWire3.wire rdata_rp_fromWire4.wire
|
||||
BUILT_SOURCES += rdata_rp_fromWire5.wire rdata_rp_fromWire6.wire
|
||||
BUILT_SOURCES += rdata_rp_toWire1.wire rdata_rp_toWire2.wire
|
||||
BUILT_SOURCES += rdata_sshfp_fromWire1.wire rdata_sshfp_fromWire2.wire
|
||||
BUILT_SOURCES += rdata_afsdb_fromWire1.wire rdata_afsdb_fromWire2.wire
|
||||
BUILT_SOURCES += rdata_afsdb_fromWire3.wire rdata_afsdb_fromWire4.wire
|
||||
BUILT_SOURCES += rdata_afsdb_fromWire5.wire
|
||||
@@ -125,6 +126,7 @@ EXTRA_DIST += rdata_rp_fromWire1.spec rdata_rp_fromWire2.spec
|
||||
EXTRA_DIST += rdata_rp_fromWire3.spec rdata_rp_fromWire4.spec
|
||||
EXTRA_DIST += rdata_rp_fromWire5.spec rdata_rp_fromWire6.spec
|
||||
EXTRA_DIST += rdata_rp_toWire1.spec rdata_rp_toWire2.spec
|
||||
EXTRA_DIST += rdata_sshfp_fromWire1.spec rdata_sshfp_fromWire2.spec
|
||||
EXTRA_DIST += rdata_afsdb_fromWire1.spec rdata_afsdb_fromWire2.spec
|
||||
EXTRA_DIST += rdata_afsdb_fromWire3.spec rdata_afsdb_fromWire4.spec
|
||||
EXTRA_DIST += rdata_afsdb_fromWire5.spec
|
||||
|
8
src/lib/dns/tests/testdata/rdata_sshfp_fromWire.wire
vendored
Normal file
8
src/lib/dns/tests/testdata/rdata_sshfp_fromWire.wire
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
###
|
||||
### This data file was auto-generated from rdata_sshfp_fromWire1.spec
|
||||
###
|
||||
|
||||
# SSHFP RDATA, RDLEN=22
|
||||
0016
|
||||
# ALGORITHM=2 FINGERPRINT_TYPE=1 FINGERPRINT=123456789abcdef67890123456789abcdef67890
|
||||
02 01 123456789abcdef67890123456789abcdef67890
|
6
src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.spec
vendored
Normal file
6
src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.spec
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# A simplest form of SSHFP: all default parameters
|
||||
#
|
||||
[custom]
|
||||
sections: sshfp
|
||||
[sshfp]
|
7
src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.spec
vendored
Normal file
7
src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.spec
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# SSHFP RDATA
|
||||
#
|
||||
[custom]
|
||||
sections: sshfp
|
||||
[sshfp]
|
||||
fingerprint: 123456789abcdef67890123456789abcdef67890
|
@@ -822,6 +822,29 @@ class RP(RR):
|
||||
f.write('# MAILBOX=%s TEXT=%s\n' % (self.mailbox, self.text))
|
||||
f.write('%s %s\n' % (mailbox_wire, text_wire))
|
||||
|
||||
class SSHFP(RR):
|
||||
'''Implements rendering SSHFP RDATA in the test data format.
|
||||
|
||||
Configurable parameters are as follows (see the description of the
|
||||
same name of attribute for the default value):
|
||||
- algorithm (int): The algorithm number.
|
||||
- fingerprint_type (int): The fingerprint type.
|
||||
- fingerprint (string): The fingerprint.
|
||||
'''
|
||||
algorithm = 2
|
||||
fingerprint_type = 1
|
||||
fingerprint = '123456789abcdef67890123456789abcdef67890'
|
||||
def dump(self, f):
|
||||
if self.rdlen is None:
|
||||
self.rdlen = 2 + (len(self.fingerprint) / 2)
|
||||
else:
|
||||
self.rdlen = int(self.rdlen)
|
||||
self.dump_header(f, self.rdlen)
|
||||
f.write('# ALGORITHM=%d FINGERPRINT_TYPE=%d FINGERPRINT=%s\n' % (self.algorithm,
|
||||
self.fingerprint_type,
|
||||
self.fingerprint))
|
||||
f.write('%02x %02x %s\n' % (self.algorithm, self.fingerprint_type, self.fingerprint))
|
||||
|
||||
class MINFO(RR):
|
||||
'''Implements rendering MINFO RDATA in the test data format.
|
||||
|
||||
|
Reference in New Issue
Block a user