src/share/database/scripts/pgsql/upgrade_3.2_to_3.3.sh
src/share/database/scripts/pgsql/upgrade_3.3_to_4.0.sh
src/share/database/scripts/pgsql/upgrade_4.0_to_5.0.sh
+ src/share/database/scripts/pgsql/upgrade_5.0_to_5.1.sh
src/share/database/scripts/pgsql/wipe_data.sh
src/share/yang/Makefile
src/share/yang/modules/Makefile
#!/bin/sh
-# Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2015-2019 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
# Verify that kea-admin lease-version returns the correct version
version=$(${keaadmin} lease-version pgsql -u $db_user -p $db_password -n $db_name)
- assert_str_eq "5.0" ${version} "Expected kea-admin to return %s, returned value was %s"
+ assert_str_eq "5.1" ${version} "Expected kea-admin to return %s, returned value was %s"
# Let's wipe the whole database
pgsql_wipe
assert_eq 1 "$output" "lease_hwaddr_source does not contain entry for HWADDR_SOURCE_UNKNOWN. (record count %d, expected %d)"
}
-pgsql_upgrade_3_0_to_5_0() {
- # Verify upgraded schema reports version 5.0.
+pgsql_upgrade_3_0_to_5_1() {
+ # Verify upgraded schema reports version 5.1.
version=$(${keaadmin} lease-version pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir)
- assert_str_eq "5.0" ${version} "Expected kea-admin to return %s, returned value was %s"
+ assert_str_eq "5.1" ${version} "Expected kea-admin to return %s, returned value was %s"
# Added user_context to lease4
output=`pgsql_execute "select user_context from lease4;"`
# Check 2.0 to 3.0 upgrade
pgsql_upgrade_2_0_to_3_0
- # Check 3.0 to 5.0 upgrade
- pgsql_upgrade_3_0_to_5_0
+ # Check 3.0 to 5.1 upgrade
+ pgsql_upgrade_3_0_to_5_1
# Let's wipe the whole database
pgsql_wipe
host_ipv4_boot_file_name_ = host->getBootFileName();
// auth_key: varchar
- auth_key_ = host->getKey().ToText();
+ auth_key_ = host->getKey().toText();
// hostname: text
hostname_ = host->getHostname();
-// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 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
namespace isc {
namespace dhcp {
-AuthKey::AuthKey(const std::string key) {
+AuthKey::AuthKey(const std::vector<uint8_t>& key) {
setAuthKey(key);
}
-AuthKey::AuthKey(void) {
+AuthKey::AuthKey(const std::string& key) {
+ setAuthKey(key);
+}
+
+AuthKey::AuthKey() {
authKey_ = AuthKey::getRandomKeyString();
}
-std::string
+std::vector<uint8_t>
AuthKey::getRandomKeyString() {
- std::vector<uint8_t> rs = isc::cryptolink::random(AuthKey::KEY_LEN);
- std::string result;
- result.resize(rs.size());
- memmove(&result[0], &rs[0], result.size());
- return (result);
+ return (isc::cryptolink::random(AuthKey::KEY_LEN));
}
-std::string
-AuthKey::ToText() const {
- // this will need enhancement if the stored container is not a string
- return (authKey_);
+std::string
+AuthKey::toText() const {
+ if (authKey_.empty()) {
+ return ("");
+ }
+ return (util::encode::encodeHex(authKey_));
}
void
-AuthKey::setAuthKey(const std::string& key) {
+AuthKey::setAuthKey(const std::vector<uint8_t>& key) {
authKey_ = key;
if (authKey_.size() > AuthKey::KEY_LEN) {
authKey_.resize(AuthKey::KEY_LEN);
}
}
+void
+AuthKey::setAuthKey(const std::string& key) {
+ if (key.empty()) {
+ authKey_.clear();
+ }
+ try {
+ std::vector<uint8_t> bin;
+ util::encode::decodeHex(key, bin);
+ setAuthKey(bin);
+ } catch (const std::exception& ex) {
+ isc_throw(BadValue, "bad auth key: " << ex.what());
+ }
+}
+
bool
AuthKey::operator==(const AuthKey& other) const {
return (authKey_ == other.authKey_);
next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
server_host_name_(server_host_name), boot_file_name_(boot_file_name),
host_id_(0), cfg_option4_(new CfgOption()),
- cfg_option6_(new CfgOption()), negative_(false),
+ cfg_option6_(new CfgOption()), negative_(false),
key_(auth_key) {
// Initialize host identifier.
// Set auth key
//@todo: uncomment once storing in configuration file is enabled
- //map->set("auth-key", Element::create(getKey().ToText()));
-
+ //map->set("auth-key", Element::create(getKey().toText()));
+
return (map);
}
// Add boot file name.
s << " file=" << (boot_file_name_.empty() ? "(empty)" : boot_file_name_);
- s << " key=" << (key_.ToText().empty() ? "(empty)" : key_.ToText());
+ s << " key=" << (key_.toText().empty() ? "(empty)" : key_.toText());
if (ipv6_reservations_.empty()) {
s << " ipv6_reservations=(none)";
-// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 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
/// @brief HostID (used only when storing in MySQL, PostgreSQL or Cassandra)
typedef uint64_t HostID;
-/// @brief Authentication keys
-///
-/// This class represents authentication keys to be used for
-/// calculating HMAC in the authentication field of the recofigure message
+/// @brief Authentication keys.
+///
+/// This class represents authentication keys to be used for
+/// calculating HMAC in the authentication field of the recofigure message.
class AuthKey {
public:
- /// @brief Length of the key - 128 bits
+ /// @brief Length of the key - 128 bits.
const static uint8_t KEY_LEN = 16;
- /// @brief Constructor
+ /// @brief Constructor.
///
/// Constructor for assigning auth keys in host reservation.
/// Ensures the key length is not greater than 16 bytes.
- /// @param key auth key to be stored
- AuthKey(const std::string key);
-
- /// @brief Constructor
+ /// @param key auth key in binary to be stored.
+ AuthKey(const std::vector<uint8_t>& key);
+
+ /// @brief Constructor.
+ ///
+ /// Constructor for assigning auth keys in host reservation.
+ /// Ensures the key length is not greater than 16 bytes.
+ /// @param key auth key in hexadecimal to be stored.
+ AuthKey(const std::string& key);
+
+ /// @brief Constructor.
///
/// Constructor for generating auth keys, with no argument.
/// shall use the internal function for generationg random keys.
AuthKey();
- // @brief get random string
+ // @brief Get random string.
///
/// Random string is generated by default will be used for
/// the keys to be used for signing Reconfigure Message.
- /// @return auth keys
- /// @todo Move randomization function to cryptolink
- static std::string getRandomKeyString();
+ /// @return Random binary string of 16 bytes.
+ static std::vector<uint8_t> getRandomKeyString();
- /// @brief set auth key value
+ /// @brief Set auth key value from binary.
///
/// Set the key value.
- // If the size is greater than 16 bytes, we resize to 16 Bytes
- /// Doesnt throw an exception
- /// @param key auth key to be stored
+ // If the size is greater than 16 bytes, we resize to 16 bytes.
+ /// Doesnt throw an exception.
+ /// @param key auth key in binary to be stored
+ void setAuthKey(const std::vector<uint8_t>& key);
+
+ /// @brief Set auth key value from hexadecimal.
+ ///
+ /// Set the key value.
+ /// If the size is greater than 16 bytes, we resize to 16 bytes.
+ /// @param key auth key in hexadecimal to be stored.
+ /// @throw BadValue if the string is not a valid hexadecimal encoding.
void setAuthKey(const std::string& key);
- /// @brief return auth key
+ /// @brief Return auth key.
///
- /// @return auth key
- std::string getAuthKey() {
+ /// @return auth key in binary.
+ const std::vector<uint8_t>& getAuthKey() const {
return authKey_;
}
- /// @brief return text format for keys
+ /// @brief Return text format for keys.
///
- /// Although returning member would have sufficed
- /// this is added incase in future authkey is no longer std::string
- std::string ToText() const;
+ /// @return auth key in hexadecimal.
+ std::string toText() const;
- ///
- /// @brief equality operator
///
- /// equality operator to compare two AuthKey classes
- /// @param other Authkey to be compared against
+ /// @brief Equality operator.
+ ///
+ /// equality operator to compare two AuthKey objects.
+ /// @param other Authkey to be compared against.
bool operator==(const AuthKey& other) const;
- /// @brief inequality operator
+ /// @brief Inequality operator.
///
- /// inequality operator to compare two AuthKey classes
- /// @param other Authkey to be compared against
+ /// inequality operator to compare two AuthKey objects.
+ /// @param other Authkey to be compared against.
bool operator!=(const AuthKey& other) const;
private:
- std::string authKey_;
+ std::vector<uint8_t> authKey_;
};
/// @brief IPv6 reservation for a host.
///
/// @return Element representation of the host
isc::data::ElementPtr toElement6() const;
-
+
/// @brief sets key.
///
/// Keys are used for signing the Reconfigure Message.
void setKey(const AuthKey& key) {
key_ = key;
}
-
+
/// @brief Returns the key.
///
/// Keys are used for signing the Reconfigure Message.
/// @brief Maximum length of the boot file name.
const size_t BOOT_FILE_NAME_MAX_LEN = 128;
-/// @brief Maximum length of keys.
-const size_t KEY_LEN = 16;
+/// @brief Maximum length of keys (coded in hexadecimal).
+const size_t KEY_LEN = 16 * 2;
/// @brief Numeric value representing last supported identifier.
///
// auth key
bind_[13].buffer_type = MYSQL_TYPE_STRING;
- std::string auth_key = host->getKey().ToText();
+ std::string auth_key = host->getKey().toText();
std::strncpy(auth_key_, auth_key.c_str(), KEY_LEN);
auth_key_null_ = auth_key.empty() ? MLM_TRUE : MLM_FALSE;
bind_[13].buffer = auth_key_;
bind_array->add(host->getBootFileName());
// add auth keys
- std::string key = host->getKey().ToText();
+ std::string key = host->getKey().toText();
if (key.empty()) {
bind_array->addNull();
} else {
-// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 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
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
#include <cstdlib>
-#include <unordered_map>
+#include <unordered_set>
#include <sstream>
+#include <boost/functional/hash.hpp>
using namespace isc;
using namespace isc::dhcp;
std::string(), std::string(),
IOAddress("192.0.0.2"),
"server-hostname.example.org",
- "bootfile.efi", AuthKey("key123"))));
+ "bootfile.efi", AuthKey("12345678"))));
// The HW address should be set to non-null.
HWAddrPtr hwaddr = host->getHWAddress();
ASSERT_TRUE(hwaddr);
EXPECT_EQ("192.0.0.2", host->getNextServer().toText());
EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
EXPECT_EQ("bootfile.efi", host->getBootFileName());
- EXPECT_EQ("key123", host->getKey().ToText());
+ EXPECT_EQ("12345678", host->getKey().toText());
EXPECT_FALSE(host->getContext());
// Use invalid identifier name
std::string(), std::string(),
IOAddress("192.0.0.2"),
"server-hostname.example.org",
- "bootfile.efi", AuthKey("keyabc"))));
+ "bootfile.efi", AuthKey("0abc1234"))));
// Hardware address should be non-null.
HWAddrPtr hwaddr = host->getHWAddress();
EXPECT_EQ("192.0.0.2", host->getNextServer().toText());
EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
EXPECT_EQ("bootfile.efi", host->getBootFileName());
- EXPECT_EQ("keyabc", host->getKey().ToText());
+ EXPECT_EQ("0ABC1234", host->getKey().toText());
EXPECT_FALSE(host->getContext());
}
host->setNextServer(IOAddress("192.0.2.2"));
host->setServerHostname("server-hostname.example.org");
host->setBootFileName("bootfile.efi");
- host->setKey(AuthKey("random-value"));
+ const std::vector<uint8_t>& random_value(AuthKey::getRandomKeyString());
+ host->setKey(AuthKey(random_value));
std::string user_context = "{ \"foo\": \"bar\" }";
host->setContext(Element::fromJSON(user_context));
host->setNegative(true);
EXPECT_EQ("192.0.2.2", host->getNextServer().toText());
EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
EXPECT_EQ("bootfile.efi", host->getBootFileName());
- EXPECT_EQ("random-value", host->getKey().ToText());
+ EXPECT_EQ(random_value, host->getKey().getAuthKey());
ASSERT_TRUE(host->getContext());
EXPECT_EQ(user_context, host->getContext()->str());
EXPECT_TRUE(host->getNegative());
// Create global host identified by DUID, with a very basic configuration.
ASSERT_NO_THROW(host.reset(new Host("11:12:13:14:15", "duid",
- SUBNET_ID_GLOBAL, SUBNET_ID_GLOBAL,
+ SUBNET_ID_GLOBAL, SUBNET_ID_GLOBAL,
IOAddress::IPV4_ZERO_ADDRESS(),
"myhost")));
// Create host identified by DUID, instead of HWADDR, with a very
// basic configuration.
ASSERT_NO_THROW(host.reset(new Host("11:12:13:14:15", "duid",
- SUBNET_ID_UNUSED, SUBNET_ID_UNUSED,
+ SUBNET_ID_UNUSED, SUBNET_ID_UNUSED,
IOAddress::IPV4_ZERO_ADDRESS(),
"myhost")));
SubnetID(1), SubnetID(2),
IOAddress("192.0.2.3"),
"myhost.example.com")));
-//Key must be empty
- EXPECT_EQ(0,host->getKey().ToText().length());
-
- //now set to random value
- host->setKey(AuthKey("random_key"));
- EXPECT_EQ("random_key", host->getKey().ToText());
+ // Key must be empty
+ EXPECT_EQ(0, host->getKey().getAuthKey().size());
+ EXPECT_EQ("", host->getKey().toText());
+
+ // now set to random value
+ const std::vector<uint8_t>& random_key(AuthKey::getRandomKeyString());
+ host->setKey(AuthKey(random_key));
+ EXPECT_EQ(random_key, host->getKey().getAuthKey());
}
-// Test verifies if getRandomKeyString can generate 1000 keys which are random
+// Test verifies if getRandomKeyString can generate 1000 keys which are random
TEST_F(HostTest, randomKeys) {
- //use hashtable and set size to 1000
- std::unordered_map<std::string, int> key_map;
-
+ // use hashtable and set size to 1000
+ std::unordered_set<std::vector<uint8_t>,
+ boost::hash<std::vector<uint8_t>>> keys;
+
int dup_element = 0;
const uint16_t max_iter = 1000;
uint16_t iter_num = 0;
size_t max_hash_size = 1000;
- key_map.reserve(max_hash_size);
+ keys.reserve(max_hash_size);
for (iter_num = 0; iter_num < max_iter; iter_num++) {
- std::string key = AuthKey::getRandomKeyString();
- if (key_map[key]) {
+ std::vector<uint8_t> key = AuthKey::getRandomKeyString();
+ if (keys.count(key)) {
dup_element++;
break;
}
- key_map[key] = 1;
+ keys.insert(key);
}
EXPECT_EQ(0, dup_element);
}
-//Test performs basic functionality test of the AuthKey class
+// Test performs basic functionality test of the AuthKey class
TEST(AuthKeyTest, basicTest) {
- //call the constructor with default argument
+ // Call the constructor with default argument
// Default constructor should generate random string of 16 bytes
AuthKey defaultKey;
ASSERT_EQ(16, defaultKey.getAuthKey().size());
-
- AuthKey longKey("someRandomStringGreaterThan16Bytes");
+
+ AuthKey longKey("0123456789abcdef1122334455667788");
ASSERT_EQ(16, longKey.getAuthKey().size());
- //check the setters for valid and invalid string
- std::string key16ByteStr = "0123456789abcdef";
+ // Check the setters for valid and invalid string
+ std::string key16ByteStr = "000102030405060708090A0B0C0D0E0F";
+ std::vector<uint8_t> key16ByteBin = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf
+ };
std::string key18ByteStr = "0123456789abcdefgh";
-
+
AuthKey defaultTestKey;
defaultTestKey.setAuthKey(key16ByteStr);
ASSERT_EQ(16, defaultTestKey.getAuthKey().size());
- ASSERT_EQ(key16ByteStr, defaultTestKey.getAuthKey());
- ASSERT_EQ(key16ByteStr, defaultTestKey.ToText());
-
- defaultTestKey.setAuthKey(key18ByteStr);
- ASSERT_EQ(16, defaultTestKey.getAuthKey().size());
- ASSERT_EQ(key16ByteStr, defaultTestKey.getAuthKey());
- ASSERT_EQ(key16ByteStr, defaultTestKey.ToText());
+ ASSERT_EQ(key16ByteStr, defaultTestKey.toText());
+ ASSERT_EQ(key16ByteBin, defaultTestKey.getAuthKey());
+ ASSERT_THROW(defaultTestKey.setAuthKey(key18ByteStr), BadValue);
}
} // end of anonymous namespace
namespace isc {
namespace db {
-/// @brief Define PostgreSQL backend version: 5.0
+/// @brief Define PostgreSQL backend version: 5.1
const uint32_t PG_SCHEMA_VERSION_MAJOR = 5;
-const uint32_t PG_SCHEMA_VERSION_MINOR = 0;
+const uint32_t PG_SCHEMA_VERSION_MINOR = 1;
// Maximum number of parameters that can be used a statement
// @todo This allows us to use an initializer list (since we can't
END $$
DELIMITER ;
+# Put the auth key in hexadecimal (double size but far more user friendly).
+ALTER TABLE hosts
+ MODIFY COLUMN auth_key VARCHAR(32) NULL;
+
# Update the schema version number
UPDATE schema_version
SET version = '8', minor = '1';
END $$
DELIMITER ;
+# Put the auth key in hexadecimal (double size but far more user friendly).
+ALTER TABLE hosts
+ MODIFY COLUMN auth_key VARCHAR(32) NULL;
+
# Update the schema version number
UPDATE schema_version
SET version = '8', minor = '1';
/upgrade_3.2_to_3.3.sh
/upgrade_3.3_to_4.0.sh
/upgrade_4.0_to_5.0.sh
+/upgrade_5.0_to_5.1.sh
/wipe_data.sh
sqlscripts_DATA += upgrade_3.2_to_3.3.sh
sqlscripts_DATA += upgrade_3.3_to_4.0.sh
sqlscripts_DATA += upgrade_4.0_to_5.0.sh
+sqlscripts_DATA += upgrade_5.0_to_5.1.sh
sqlscripts_DATA += wipe_data.sh
DISTCLEANFILES = upgrade_1.0_to_2.0.sh
DISTCLEANFILES += upgrade_3.2_to_3.3.sh
DISTCLEANFILES += upgrade_3.3_to_4.0.sh
DISTCLEANFILES += upgrade_4.0_to_5.0.sh
+DISTCLEANFILES += upgrade_5.0_to_5.1.sh
DISTCLEANFILES += wipe_data.sh
EXTRA_DIST = ${sqlscripts_DATA}
--- Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
+-- Copyright (C) 2012-2019 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
-- Schema 5.0 specification ends here.
+-- Upgrade to schema 5.1 begins here:
+
+-- Put the auth key in hexadecimal (double size but far more user friendly).
+ALTER TABLE hosts ALTER COLUMN auth_key TYPE VARCHAR(32);
+
+-- Set schema 5.1 version
+UPDATE schema_version
+ SET version = '5', minor = '1';
+
+-- Schema 5.1 specification ends here.
+
-- Commit the script transaction.
COMMIT;
--- /dev/null
+#!/bin/sh
+
+prefix=@prefix@
+# Include utilities. Use installed version if available and
+# use build version if it isn't.
+if [ -e @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh ]; then
+ . @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh
+else
+ . @abs_top_builddir@/src/bin/admin/admin-utils.sh
+fi
+
+VERSION=`pgsql_version "$@"`
+
+if [ "$VERSION" != "5.0" ]; then
+ printf "This script upgrades 5.0 to 5.1. Reported version is $VERSION. Skipping upgrade.\n"
+ exit 0
+fi
+
+psql "$@" >/dev/null <<EOF
+
+START TRANSACTION;
+
+-- Put the auth key in hexadecimal (double size but far more user friendly).
+ALTER TABLE hosts ALTER COLUMN auth_key TYPE VARCHAR(32);
+
+-- Set 5.1 schema version.
+UPDATE schema_version
+ SET version = '5', minor = '1';
+
+-- Schema 5.1a specification ends here.
+
+-- Commit the script transaction
+COMMIT;
+
+EOF
+
+exit $RESULT
+