Check that filesystem id didn't change since we loaded the basedir the last time
This commit is contained in:
parent
26b3b366c9
commit
aace4c2f13
@ -21,6 +21,8 @@
|
||||
#include "VersionChecker.h"
|
||||
#include <gitversion/VersionCompare.h>
|
||||
#include <cpp-utils/io/NoninteractiveConsole.h>
|
||||
#include <cryfs/localstate/LocalStateDir.h>
|
||||
#include <cryfs/localstate/BasedirMetadata.h>
|
||||
#include "Environment.h"
|
||||
|
||||
//TODO Many functions accessing the ProgramOptions object. Factor out into class that stores it as a member.
|
||||
@ -195,6 +197,17 @@ namespace cryfs {
|
||||
return *configFile;
|
||||
}
|
||||
|
||||
void Cli::_checkConfigIntegrity(const bf::path& basedir, const CryConfigFile& config) {
|
||||
if (!BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir, config.config()->FilesystemId())) {
|
||||
if (!_console->askYesNo("The filesystem id in the config file is different to the last time we loaded a filesystem from this basedir. This can be genuine if you replaced the filesystem with a different one. If you didn't do that, it is possible that an attacker did. Do you want to continue loading the file system?", false)) {
|
||||
throw std::runtime_error(
|
||||
"The filesystem id in the config file is different to the last time we loaded a filesystem from this basedir.");
|
||||
}
|
||||
}
|
||||
// Update local state (or create it if it didn't exist yet)
|
||||
BasedirMetadata::updateFilesystemIdForBasedir(basedir, config.config()->FilesystemId());
|
||||
}
|
||||
|
||||
CryConfigLoader::ConfigLoadResult Cli::_loadOrCreateConfig(const ProgramOptions &options) {
|
||||
try {
|
||||
auto configFile = _determineConfigFile(options);
|
||||
@ -203,6 +216,7 @@ namespace cryfs {
|
||||
std::cerr << "Could not load config file. Did you enter the correct password?" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
_checkConfigIntegrity(options.baseDir(), config->configFile);
|
||||
return std::move(*config);
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
|
@ -23,6 +23,7 @@ namespace cryfs {
|
||||
void _checkForUpdates();
|
||||
void _runFilesystem(const program_options::ProgramOptions &options);
|
||||
CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options);
|
||||
void _checkConfigIntegrity(const boost::filesystem::path& basedir, const CryConfigFile& config);
|
||||
boost::optional<CryConfigLoader::ConfigLoadResult> _loadOrCreateConfigFile(const boost::filesystem::path &configFilePath, const boost::optional<std::string> &cipher, const boost::optional<uint32_t> &blocksizeBytes, const boost::optional<bool> &missingBlockIsIntegrityViolation);
|
||||
boost::filesystem::path _determineConfigFile(const program_options::ProgramOptions &options);
|
||||
static std::string _askPasswordForExistingFilesystem();
|
||||
|
@ -42,6 +42,7 @@ set(LIB_SOURCES
|
||||
filesystem/CryDevice.cpp
|
||||
localstate/LocalStateDir.cpp
|
||||
localstate/LocalStateMetadata.cpp
|
||||
localstate/BasedirMetadata.cpp
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${LIB_SOURCES})
|
||||
|
82
src/cryfs/localstate/BasedirMetadata.cpp
Normal file
82
src/cryfs/localstate/BasedirMetadata.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include "BasedirMetadata.h"
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <cryptopp/sha.h>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include "LocalStateDir.h"
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
using boost::property_tree::ptree;
|
||||
using boost::property_tree::write_json;
|
||||
using boost::property_tree::read_json;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
using std::ostream;
|
||||
using std::istream;
|
||||
using std::ifstream;
|
||||
using std::ofstream;
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
namespace {
|
||||
bf::path _localStateConfigFile(const bf::path& basedir) {
|
||||
std::string basedir_id;
|
||||
CryptoPP::SHA512 hash;
|
||||
CryptoPP::StringSource(bf::canonical(basedir).native(), true,
|
||||
new CryptoPP::HashFilter(hash,
|
||||
new CryptoPP::HexEncoder(
|
||||
new CryptoPP::StringSink(basedir_id)
|
||||
)
|
||||
)
|
||||
);
|
||||
return LocalStateDir::forMapFromBasedirToConfigFiles() / basedir_id;
|
||||
}
|
||||
|
||||
void _serialize(ostream& stream, const CryConfig::FilesystemID& filesystemId) {
|
||||
ptree pt;
|
||||
pt.put<std::string>("filesystemId", filesystemId.ToString());
|
||||
|
||||
write_json(stream, pt);
|
||||
}
|
||||
|
||||
CryConfig::FilesystemID _deserialize(istream& stream) {
|
||||
ptree pt;
|
||||
read_json(stream, pt);
|
||||
|
||||
std::string filesystemId = pt.get<std::string>("filesystemId");
|
||||
|
||||
return CryConfig::FilesystemID::FromString(filesystemId);
|
||||
}
|
||||
|
||||
optional<CryConfig::FilesystemID> _load(const bf::path &metadataFilePath) {
|
||||
ifstream file(metadataFilePath.native());
|
||||
if (!file.good()) {
|
||||
// State file doesn't exist
|
||||
return none;
|
||||
}
|
||||
return _deserialize(file);
|
||||
}
|
||||
|
||||
void _save(const bf::path &metadataFilePath, const CryConfig::FilesystemID& filesystemId) {
|
||||
ofstream file(metadataFilePath.native(), std::ios::trunc);
|
||||
_serialize(file, filesystemId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool BasedirMetadata::filesystemIdForBasedirIsCorrect(const bf::path &basedir, const CryConfig::FilesystemID &filesystemId) {
|
||||
auto metadataFile = _localStateConfigFile(basedir);
|
||||
auto loaded = _load(metadataFile);
|
||||
if (loaded == none) {
|
||||
// Local state not known. Possibly the file system is currently being created.
|
||||
return true;
|
||||
}
|
||||
return loaded == filesystemId;
|
||||
}
|
||||
|
||||
void BasedirMetadata::updateFilesystemIdForBasedir(const bf::path &basedir, const CryConfig::FilesystemID &filesystemId) {
|
||||
auto metadataFile = _localStateConfigFile(basedir);
|
||||
_save(metadataFile, filesystemId);
|
||||
}
|
||||
|
||||
}
|
18
src/cryfs/localstate/BasedirMetadata.h
Normal file
18
src/cryfs/localstate/BasedirMetadata.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_LOCALSTATE_BASEDIRMETADATA_H_
|
||||
#define MESSMER_CRYFS_LOCALSTATE_BASEDIRMETADATA_H_
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include "../config/CryConfig.h"
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
class BasedirMetadata final {
|
||||
public:
|
||||
static bool filesystemIdForBasedirIsCorrect(const boost::filesystem::path &basedir, const CryConfig::FilesystemID &filesystemId);
|
||||
static void updateFilesystemIdForBasedir(const boost::filesystem::path &basedir, const CryConfig::FilesystemID &filesystemId);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -5,19 +5,36 @@
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
namespace cryfs {
|
||||
namespace {
|
||||
// TODO constexpr?
|
||||
bf::path& appDir() {
|
||||
static bf::path singleton = cpputils::system::HomeDirectory::get() / ".cryfs";
|
||||
return singleton;
|
||||
}
|
||||
}
|
||||
|
||||
bf::path LocalStateDir::forFilesystemId(const CryConfig::FilesystemID &filesystemId) {
|
||||
bf::path app_dir = cpputils::system::HomeDirectory::get() / ".cryfs";
|
||||
_createDirIfNotExists(app_dir);
|
||||
bf::path filesystems_dir = app_dir / "filesystems";
|
||||
_createDirIfNotExists(appDir());
|
||||
bf::path filesystems_dir = appDir() / "filesystems";
|
||||
_createDirIfNotExists(filesystems_dir);
|
||||
bf::path this_filesystem_dir = filesystems_dir / filesystemId.ToString();
|
||||
_createDirIfNotExists(this_filesystem_dir);
|
||||
return this_filesystem_dir;
|
||||
}
|
||||
|
||||
bf::path LocalStateDir::forMapFromBasedirToConfigFiles() {
|
||||
bf::path result = appDir() / "map_basedir_initialconfigfile";
|
||||
_createDirIfNotExists(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void LocalStateDir::_createDirIfNotExists(const bf::path &path) {
|
||||
if (!bf::exists(path)) {
|
||||
bf::create_directory(path);
|
||||
bf::create_directories(path);
|
||||
}
|
||||
}
|
||||
|
||||
void LocalStateDir::setAppDir(boost::filesystem::path path) {
|
||||
appDir() = std::move(path);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,11 @@ namespace cryfs {
|
||||
class LocalStateDir final {
|
||||
public:
|
||||
static boost::filesystem::path forFilesystemId(const CryConfig::FilesystemID &filesystemId);
|
||||
static boost::filesystem::path forMapFromBasedirToConfigFiles();
|
||||
|
||||
// Use this from test cases to not pollute local config
|
||||
// TODO Make test cases call this
|
||||
static void setAppDir(boost::filesystem::path path);
|
||||
|
||||
private:
|
||||
LocalStateDir(); // static functions only
|
||||
|
@ -67,7 +67,7 @@ optional<uint32_t> _tryLoadClientIdFromLegacyFile(const bf::path &metadataFilePa
|
||||
uint32_t value;
|
||||
file >> value;
|
||||
file.close();
|
||||
//bf::remove(myClientIdFile);
|
||||
bf::remove(myClientIdFile);
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
@ -17,7 +17,8 @@ set(SOURCES
|
||||
filesystem/CryFsTest.cpp
|
||||
filesystem/CryNodeTest.cpp
|
||||
filesystem/FileSystemTest.cpp
|
||||
localstate/LocalStateMetadataTest.cpp
|
||||
localstate/LocalStateMetadataTest.cpp
|
||||
localstate/BasedirMetadataTest.cpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
|
67
test/cryfs/localstate/BasedirMetadataTest.cpp
Normal file
67
test/cryfs/localstate/BasedirMetadataTest.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cryfs/localstate/BasedirMetadata.h>
|
||||
#include <cryfs/localstate/LocalStateDir.h>
|
||||
#include <cryfs/config/CryConfig.h>
|
||||
#include <cpp-utils/tempfile/TempDir.h>
|
||||
|
||||
using cpputils::TempDir;
|
||||
using cryfs::BasedirMetadata;
|
||||
using std::ofstream;
|
||||
namespace bf = boost::filesystem;
|
||||
using FilesystemID = cryfs::CryConfig::FilesystemID ;
|
||||
|
||||
class BasedirMetadataTest : public ::testing::Test {
|
||||
public:
|
||||
TempDir tempdir;
|
||||
bf::path basedir1;
|
||||
bf::path basedir2;
|
||||
const FilesystemID id1;
|
||||
const FilesystemID id2;
|
||||
|
||||
BasedirMetadataTest()
|
||||
: tempdir()
|
||||
, basedir1(tempdir.path() / "my/basedir")
|
||||
, basedir2(tempdir.path() / "my/other/basedir")
|
||||
, id1(FilesystemID::FromString("1491BB4932A389EE14BC7090AC772972"))
|
||||
, id2(FilesystemID::FromString("A1491BB493214BC7090C772972A389EE"))
|
||||
{
|
||||
// Use temporary local state dir to not pollute local state
|
||||
cryfs::LocalStateDir::setAppDir(tempdir.path() / "appdir");
|
||||
// Create basedirs so bf::canonical() works
|
||||
bf::create_directories(basedir1);
|
||||
bf::create_directories(basedir2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TEST_F(BasedirMetadataTest, givenEmptyState_whenCalled_thenSucceeds) {
|
||||
EXPECT_TRUE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
|
||||
}
|
||||
|
||||
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledForDifferentBasedir_thenSucceeds) {
|
||||
BasedirMetadata::updateFilesystemIdForBasedir(basedir2, id1);
|
||||
EXPECT_TRUE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
|
||||
}
|
||||
|
||||
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithSameId_thenSucceeds) {
|
||||
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id1);
|
||||
EXPECT_TRUE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
|
||||
}
|
||||
|
||||
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithDifferentId_thenFails) {
|
||||
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id2);
|
||||
EXPECT_FALSE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
|
||||
}
|
||||
|
||||
TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithSameId_thenSucceeds) {
|
||||
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id2);
|
||||
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id1);
|
||||
EXPECT_TRUE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
|
||||
}
|
||||
|
||||
TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithDifferentId_thenFails) {
|
||||
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id2);
|
||||
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id1);
|
||||
EXPECT_FALSE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id2));
|
||||
}
|
Loading…
Reference in New Issue
Block a user