lib/net: Implement a reusable fingerprint database
This commit is contained in:
parent
3e71b468f6
commit
9cac96b4af
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
barrier -- mouse and keyboard sharing utility
|
||||||
|
Copyright (C) Barrier contributors
|
||||||
|
|
||||||
|
This package is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
found in the file LICENSE that should have accompanied this file.
|
||||||
|
|
||||||
|
This package is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "base/String.h"
|
||||||
|
#include "FingerprintDatabase.h"
|
||||||
|
#include "io/fstream.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace barrier {
|
||||||
|
|
||||||
|
bool FingerprintData::operator==(const FingerprintData& other) const
|
||||||
|
{
|
||||||
|
return algorithm == other.algorithm && data == other.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FingerprintDatabase::read(const std::string& path)
|
||||||
|
{
|
||||||
|
std::ifstream file;
|
||||||
|
open_utf8_path(file, path, std::ios_base::in);
|
||||||
|
read_stream(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FingerprintDatabase::write(const std::string& path)
|
||||||
|
{
|
||||||
|
std::ofstream file;
|
||||||
|
open_utf8_path(file, path, std::ios_base::out);
|
||||||
|
write_stream(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FingerprintDatabase::read_stream(std::istream& stream)
|
||||||
|
{
|
||||||
|
if (!stream.good()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(stream, line)) {
|
||||||
|
if (line.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fingerprint = parse_db_line(line);
|
||||||
|
if (!fingerprint.valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fingerprints_.push_back(fingerprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FingerprintDatabase::write_stream(std::ostream& stream)
|
||||||
|
{
|
||||||
|
if (!stream.good()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& fingerprint : fingerprints_) {
|
||||||
|
stream << to_db_line(fingerprint) << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FingerprintDatabase::clear()
|
||||||
|
{
|
||||||
|
fingerprints_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FingerprintDatabase::add_trusted(const FingerprintData& fingerprint)
|
||||||
|
{
|
||||||
|
if (is_trusted(fingerprint)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fingerprints_.push_back(fingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FingerprintDatabase::is_trusted(const FingerprintData& fingerprint)
|
||||||
|
{
|
||||||
|
auto found_it = std::find(fingerprints_.begin(), fingerprints_.end(), fingerprint);
|
||||||
|
return found_it != fingerprints_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
FingerprintData FingerprintDatabase::parse_db_line(const std::string& line)
|
||||||
|
{
|
||||||
|
FingerprintData result;
|
||||||
|
|
||||||
|
// legacy v1 certificate handling
|
||||||
|
if (std::count(line.begin(), line.end(), ':') == 19 && line.size() == 40 + 19) {
|
||||||
|
auto data = string::from_hex(line);
|
||||||
|
if (data.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.algorithm = fingerprint_type_to_string(FingerprintType::SHA1);
|
||||||
|
result.data = data;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto version_end_pos = line.find(':');
|
||||||
|
if (version_end_pos == std::string::npos) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (line.substr(0, version_end_pos) != "v2") {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
auto algo_start_pos = version_end_pos + 1;
|
||||||
|
auto algo_end_pos = line.find(':', algo_start_pos);
|
||||||
|
if (algo_end_pos == std::string::npos) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
auto algorithm = line.substr(algo_start_pos, algo_end_pos - algo_start_pos);
|
||||||
|
auto data = string::from_hex(line.substr(algo_end_pos + 1));
|
||||||
|
|
||||||
|
if (data.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.algorithm = algorithm;
|
||||||
|
result.data = data;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FingerprintDatabase::to_db_line(const FingerprintData& fingerprint)
|
||||||
|
{
|
||||||
|
return "v2:" + fingerprint.algorithm + ":" + string::to_hex(fingerprint.data, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace barrier
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
barrier -- mouse and keyboard sharing utility
|
||||||
|
Copyright (C) Barrier contributors
|
||||||
|
|
||||||
|
This package is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
found in the file LICENSE that should have accompanied this file.
|
||||||
|
|
||||||
|
This package is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
|
||||||
|
#define BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
|
||||||
|
|
||||||
|
#include "FingerprintType.h"
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace barrier {
|
||||||
|
|
||||||
|
struct FingerprintData {
|
||||||
|
std::string algorithm;
|
||||||
|
std::vector<std::uint8_t> data;
|
||||||
|
|
||||||
|
bool valid() const { return !algorithm.empty(); }
|
||||||
|
|
||||||
|
bool operator==(const FingerprintData& other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FingerprintDatabase {
|
||||||
|
public:
|
||||||
|
void read(const std::string& path);
|
||||||
|
void write(const std::string& path);
|
||||||
|
|
||||||
|
void read_stream(std::istream& stream);
|
||||||
|
void write_stream(std::ostream& stream);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void add_trusted(const FingerprintData& fingerprint);
|
||||||
|
bool is_trusted(const FingerprintData& fingerprint);
|
||||||
|
|
||||||
|
const std::vector<FingerprintData>& fingerprints() const { return fingerprints_; }
|
||||||
|
|
||||||
|
static FingerprintData parse_db_line(const std::string& line);
|
||||||
|
static std::string to_db_line(const FingerprintData& fingerprint);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<FingerprintData> fingerprints_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace barrier
|
||||||
|
|
||||||
|
#endif // BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
barrier -- mouse and keyboard sharing utility
|
||||||
|
Copyright (C) Barrier contributors
|
||||||
|
|
||||||
|
This package is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
found in the file LICENSE that should have accompanied this file.
|
||||||
|
|
||||||
|
This package is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BARRIER_LIB_NET_FINGERPRINT_TYPE_H
|
||||||
|
#define BARRIER_LIB_NET_FINGERPRINT_TYPE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace barrier {
|
||||||
|
|
||||||
|
enum FingerprintType {
|
||||||
|
INVALID,
|
||||||
|
SHA1, // deprecated
|
||||||
|
SHA256,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const char* fingerprint_type_to_string(FingerprintType type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case FingerprintType::INVALID: return "invalid";
|
||||||
|
case FingerprintType::SHA1: return "sha1";
|
||||||
|
case FingerprintType::SHA256: return "sha256";
|
||||||
|
}
|
||||||
|
return "invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FingerprintType fingerprint_type_from_string(const std::string& type)
|
||||||
|
{
|
||||||
|
if (type == "sha1") {
|
||||||
|
return FingerprintType::SHA1;
|
||||||
|
}
|
||||||
|
if (type == "sha256") {
|
||||||
|
return FingerprintType::SHA256;
|
||||||
|
}
|
||||||
|
return FingerprintType::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace barrier
|
||||||
|
|
||||||
|
#endif // BARRIER_LIB_NET_FINGERPRINT_TYPE_H
|
|
@ -18,6 +18,7 @@
|
||||||
#ifndef BARRIER_LIB_NET_SECUREUTILS_H
|
#ifndef BARRIER_LIB_NET_SECUREUTILS_H
|
||||||
#define BARRIER_LIB_NET_SECUREUTILS_H
|
#define BARRIER_LIB_NET_SECUREUTILS_H
|
||||||
|
|
||||||
|
#include "FingerprintType.h"
|
||||||
#include <openssl/ossl_typ.h>
|
#include <openssl/ossl_typ.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -25,11 +26,6 @@
|
||||||
|
|
||||||
namespace barrier {
|
namespace barrier {
|
||||||
|
|
||||||
enum FingerprintType {
|
|
||||||
SHA1, // deprecated
|
|
||||||
SHA256,
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string format_ssl_fingerprint(const std::vector<std::uint8_t>& fingerprint,
|
std::string format_ssl_fingerprint(const std::vector<std::uint8_t>& fingerprint,
|
||||||
bool separator = true);
|
bool separator = true);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
barrier -- mouse and keyboard sharing utility
|
||||||
|
Copyright (C) Barrier contributors
|
||||||
|
|
||||||
|
This package is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
found in the file LICENSE that should have accompanied this file.
|
||||||
|
|
||||||
|
This package is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "net/FingerprintDatabase.h"
|
||||||
|
#include "test/global/gtest.h"
|
||||||
|
|
||||||
|
namespace barrier {
|
||||||
|
|
||||||
|
TEST(FingerprintDatabase, parse_db_line)
|
||||||
|
{
|
||||||
|
ASSERT_FALSE(FingerprintDatabase::parse_db_line("").valid());
|
||||||
|
ASSERT_FALSE(FingerprintDatabase::parse_db_line("abcd").valid());
|
||||||
|
ASSERT_FALSE(FingerprintDatabase::parse_db_line("v1:algo:something").valid());
|
||||||
|
ASSERT_FALSE(FingerprintDatabase::parse_db_line("v2:algo:something").valid());
|
||||||
|
ASSERT_FALSE(FingerprintDatabase::parse_db_line("v2:algo:01020304abc").valid());
|
||||||
|
ASSERT_FALSE(FingerprintDatabase::parse_db_line("v2:algo:01020304ZZ").valid());
|
||||||
|
ASSERT_EQ(FingerprintDatabase::parse_db_line("v2:algo:01020304ab"),
|
||||||
|
(FingerprintData{"algo", {1, 2, 3, 4, 0xab}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FingerprintDatabase, read)
|
||||||
|
{
|
||||||
|
std::istringstream stream;
|
||||||
|
stream.str(R"(
|
||||||
|
v2:algo1:01020304ab
|
||||||
|
v2:algo2:03040506ab
|
||||||
|
AB:CD:EF:00:01:02:03:04:05:06:07:08:09:10:11:12:13:14:15:16
|
||||||
|
)");
|
||||||
|
FingerprintDatabase db;
|
||||||
|
db.read_stream(stream);
|
||||||
|
|
||||||
|
std::vector<FingerprintData> expected = {
|
||||||
|
{ "algo1", { 1, 2, 3, 4, 0xab } },
|
||||||
|
{ "algo2", { 3, 4, 5, 6, 0xab } },
|
||||||
|
{ "sha1", { 0xab, 0xcd, 0xef, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||||
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 } },
|
||||||
|
};
|
||||||
|
ASSERT_EQ(db.fingerprints(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FingerprintDatabase, write)
|
||||||
|
{
|
||||||
|
std::ostringstream stream;
|
||||||
|
|
||||||
|
FingerprintDatabase db;
|
||||||
|
db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
|
||||||
|
db.add_trusted({ "algo2", { 3, 4, 5, 6, 0xab } });
|
||||||
|
db.write_stream(stream);
|
||||||
|
|
||||||
|
ASSERT_EQ(stream.str(), R"(v2:algo1:01020304ab
|
||||||
|
v2:algo2:03040506ab
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FingerprintDatabase, clear)
|
||||||
|
{
|
||||||
|
FingerprintDatabase db;
|
||||||
|
db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
|
||||||
|
db.clear();
|
||||||
|
ASSERT_TRUE(db.fingerprints().empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FingerprintDatabase, add_trusted_no_duplicates)
|
||||||
|
{
|
||||||
|
FingerprintDatabase db;
|
||||||
|
db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
|
||||||
|
db.add_trusted({ "algo2", { 3, 4, 5, 6, 0xab } });
|
||||||
|
db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
|
||||||
|
ASSERT_EQ(db.fingerprints().size(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FingerprintDatabase, is_trusted)
|
||||||
|
{
|
||||||
|
FingerprintDatabase db;
|
||||||
|
db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
|
||||||
|
ASSERT_TRUE(db.is_trusted({ "algo1", { 1, 2, 3, 4, 0xab } }));
|
||||||
|
ASSERT_FALSE(db.is_trusted({ "algo2", { 1, 2, 3, 4, 0xab } }));
|
||||||
|
ASSERT_FALSE(db.is_trusted({ "algo1", { 1, 2, 3, 4, 0xac } }));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace barrier
|
Loading…
Reference in New Issue