Skip to content

Commit

Permalink
Add encryption capability to Info* objects.
Browse files Browse the repository at this point in the history
Info objects can be stored encrypted and loaded with a cipher type and passphrase.
  • Loading branch information
dwsteele committed Nov 28, 2018
1 parent 410a04a commit 6c23830
Show file tree
Hide file tree
Showing 14 changed files with 176 additions and 52 deletions.
4 changes: 4 additions & 0 deletions doc/xml/release.xml
Expand Up @@ -35,6 +35,10 @@
<p>Add interface objects for <proper>libxml2</proper>.</p>
</release-item>

<release-item>
<p>Add encryption capability to <code>Info*</code> objects.</p>
</release-item>

<release-item>
<p>Add <code>IoFilter</code> interface to <code>CipherBlock</code> object.</p>
</release-item>
Expand Down
8 changes: 4 additions & 4 deletions src/Makefile
Expand Up @@ -165,7 +165,7 @@ install: pgbackrest
command/archive/common.o: command/archive/common.c command/archive/common.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/regExp.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h common/wait.h postgres/version.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
$(CC) $(CFLAGS) -c command/archive/common.c -o command/archive/common.o

command/archive/get/file.o: command/archive/get/file.c command/archive/common.h command/archive/get/file.h command/control/control.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h compress/gzip.h compress/gzipDecompress.h config/config.auto.h config/config.h config/define.auto.h config/define.h info/infoArchive.h info/infoPg.h postgres/interface.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
command/archive/get/file.o: command/archive/get/file.c command/archive/common.h command/archive/get/file.h command/control/control.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h compress/gzip.h compress/gzipDecompress.h config/config.auto.h config/config.h config/define.auto.h config/define.h crypto/crypto.h info/infoArchive.h info/infoPg.h postgres/interface.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
$(CC) $(CFLAGS) -c command/archive/get/file.c -o command/archive/get/file.o

command/archive/get/get.o: command/archive/get/get.c command/archive/common.h command/archive/get/file.h command/command.h common/assert.h common/debug.h common/error.auto.h common/error.h common/fork.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/regExp.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h common/wait.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/interface.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
Expand Down Expand Up @@ -330,13 +330,13 @@ crypto/crypto.o: crypto/crypto.c common/debug.h common/error.auto.h common/error
crypto/hash.o: crypto/hash.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/filter.intern.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/variant.h common/type/variantList.h crypto/crypto.h crypto/hash.h
$(CC) $(CFLAGS) -c crypto/hash.c -o crypto/hash.o

info/info.o: info/info.c common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h crypto/hash.h info/info.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h version.h
info/info.o: info/info.c common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h crypto/cipherBlock.h crypto/crypto.h crypto/hash.h info/info.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h version.h
$(CC) $(CFLAGS) -c info/info.c -o info/info.o

info/infoArchive.o: info/infoArchive.c common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h info/infoArchive.h info/infoPg.h postgres/interface.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
info/infoArchive.o: info/infoArchive.c common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h crypto/crypto.h info/infoArchive.h info/infoPg.h postgres/interface.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
$(CC) $(CFLAGS) -c info/infoArchive.c -o info/infoArchive.o

info/infoPg.o: info/infoPg.c common/assert.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h crypto/hash.h info/info.h info/infoPg.h postgres/interface.h postgres/version.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
info/infoPg.o: info/infoPg.c common/assert.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h crypto/crypto.h crypto/hash.h info/info.h info/infoPg.h postgres/interface.h postgres/version.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
$(CC) $(CFLAGS) -c info/infoPg.c -o info/infoPg.o

main.o: main.c command/archive/get/get.h command/archive/push/push.h command/command.h command/help/help.h common/debug.h common/error.auto.h common/error.h common/exit.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/interface.h version.h
Expand Down
4 changes: 3 additions & 1 deletion src/command/archive/get/file.c
Expand Up @@ -10,6 +10,7 @@ Archive Get File
#include "compress/gzip.h"
#include "compress/gzipDecompress.h"
#include "config/config.h"
#include "crypto/crypto.h"
#include "info/infoArchive.h"
#include "postgres/interface.h"
#include "storage/helper.h"
Expand All @@ -35,7 +36,8 @@ archiveGetCheck(const String *archiveFile)
PgControl controlInfo = pgControlFromFile(cfgOptionStr(cfgOptPgPath));

// Attempt to load the archive info file
InfoArchive *info = infoArchiveNew(storageRepo(), STRING_CONST(STORAGE_REPO_ARCHIVE "/" INFO_ARCHIVE_FILE), false);
InfoArchive *info = infoArchiveNew(
storageRepo(), STRING_CONST(STORAGE_REPO_ARCHIVE "/" INFO_ARCHIVE_FILE), false, cipherTypeNone, NULL);

// Loop through the pg history in case the WAL we need is not in the most recent archive id
String *archiveId = NULL;
Expand Down
69 changes: 55 additions & 14 deletions src/info/info.c
Expand Up @@ -9,6 +9,7 @@ Info Handler
#include "common/ini.h"
#include "common/log.h"
#include "common/memContext.h"
#include "crypto/cipherBlock.h"
#include "crypto/hash.h"
#include "info/info.h"
#include "storage/helper.h"
Expand All @@ -18,8 +19,14 @@ Info Handler
Internal constants
***********************************************************************************************************************************/
#define INI_COPY_EXT ".copy"

#define INI_SECTION_BACKREST "backrest"
STRING_STATIC(INI_SECTION_BACKREST_STR, INI_SECTION_BACKREST);
#define INI_SECTION_CIPHER "cipher"
STRING_STATIC(INI_SECTION_CIPHER_STR, INI_SECTION_CIPHER);

#define INI_KEY_CIPHER_PASS "cipher-pass"
STRING_STATIC(INI_KEY_CIPHER_PASS_STR, INI_KEY_CIPHER_PASS);
#define INI_KEY_FORMAT "backrest-format"
STRING_STATIC(INI_KEY_FORMAT_STR, INI_KEY_FORMAT);
#define INI_KEY_CHECKSUM "backrest-checksum"
Expand All @@ -33,6 +40,7 @@ struct Info
MemContext *memContext; // Context that contains the info
String *fileName; // Full path name of the file
Ini *ini; // Parsed file contents
const String *cipherPass; // Cipher passphrase if set
};

/***********************************************************************************************************************************
Expand Down Expand Up @@ -174,14 +182,14 @@ infoValidInternal(
Internal function to load the copy and check validity
***********************************************************************************************************************************/
static bool
loadInternal(
Info *this, // Info object to load parsed buffer into
const Storage *storage,
bool copyFile) // Is this the copy file?
loadInternal(Info *this, const Storage *storage, bool copyFile, CipherType cipherType, const String *cipherPass)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INFO, this);
FUNCTION_DEBUG_PARAM(BOOL, copyFile);
FUNCTION_DEBUG_BEGIN(logLevelTrace)
FUNCTION_DEBUG_PARAM(INFO, this); // Info object to load parsed buffer into
FUNCTION_DEBUG_PARAM(STORAGE, storage);
FUNCTION_DEBUG_PARAM(BOOL, copyFile); // Is this the copy file?
FUNCTION_DEBUG_PARAM(ENUM, cipherType);
// cipherPass omitted for security

FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
Expand All @@ -193,7 +201,18 @@ loadInternal(
String *fileName = copyFile ? strCat(strDup(this->fileName), INI_COPY_EXT) : this->fileName;

// Attempt to load the file
Buffer *buffer = storageGetNP(storageNewReadP(storage, fileName, .ignoreMissing = true));
StorageFileRead *infoRead = storageNewReadP(storage, fileName, .ignoreMissing = true);

if (cipherType != cipherTypeNone)
{
ioReadFilterGroupSet(
storageFileReadIo(infoRead),
ioFilterGroupAdd(
ioFilterGroupNew(), cipherBlockFilter(cipherBlockNew(cipherModeDecrypt, cipherType, bufNewStr(cipherPass),
NULL))));
}

Buffer *buffer = storageGetNP(infoRead);

// If the file exists, parse and validate it
if (buffer != NULL)
Expand All @@ -217,12 +236,13 @@ Load an Info object
// ??? The file MUST exist currently, so this is not actually creating the object - rather it is loading it
***********************************************************************************************************************************/
Info *
infoNew(
const Storage *storage,
const String *fileName) // Full path/filename to load
infoNew(const Storage *storage, const String *fileName, CipherType cipherType, const String *cipherPass)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, fileName);
FUNCTION_DEBUG_PARAM(STORAGE, storage);
FUNCTION_DEBUG_PARAM(STRING, fileName); // Full path/filename to load
FUNCTION_DEBUG_PARAM(ENUM, cipherType);
// cipherPass omitted for security

FUNCTION_DEBUG_ASSERT(fileName != NULL);
FUNCTION_DEBUG_END();
Expand All @@ -239,16 +259,25 @@ infoNew(
this->fileName = strDup(fileName);

// Attempt to load the main file. If it does not exist or is invalid, try to load the copy.
if (!loadInternal(this, storage, false))
if (!loadInternal(this, storage, false, cipherType, cipherPass))
{
if (!loadInternal(this, storage, true))
if (!loadInternal(this, storage, true, cipherType, cipherPass))
{
THROW_FMT(
FileMissingError, "unable to open %s or %s",
strPtr(storagePathNP(storage, this->fileName)),
strPtr(strCat(storagePathNP(storage, this->fileName), INI_COPY_EXT)));
}
}

// Load the cipher passphrase if it exists
String *cipherPass = varStr(iniGetDefault(this->ini, INI_SECTION_CIPHER_STR, INI_KEY_CIPHER_PASS_STR, NULL));

if (cipherPass != NULL)
{
this->cipherPass = strSubN(cipherPass, 1, strSize(cipherPass) - 2);
strFree(cipherPass);
}
}
MEM_CONTEXT_NEW_END();

Expand All @@ -259,6 +288,18 @@ infoNew(
/***********************************************************************************************************************************
Accessor functions
***********************************************************************************************************************************/
const String *
infoCipherPass(const Info *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INFO, this);

FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();

FUNCTION_TEST_RESULT(CONST_STRING, this->cipherPass);
}

Ini *
infoIni(const Info *this)
{
Expand Down
4 changes: 3 additions & 1 deletion src/info/info.h
Expand Up @@ -10,17 +10,19 @@ Object type
typedef struct Info Info;

#include "common/ini.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "storage/storage.h"

/***********************************************************************************************************************************
Constructor
***********************************************************************************************************************************/
Info *infoNew(const Storage *storage, const String *fileName);
Info *infoNew(const Storage *storage, const String *fileName, CipherType cipherType, const String *cipherPass);

/***********************************************************************************************************************************
Getters
***********************************************************************************************************************************/
const String *infoCipherPass(const Info *this);
String *infoFileName(const Info *this);
Ini *infoIni(const Info *this);

Expand Down
22 changes: 20 additions & 2 deletions src/info/infoArchive.c
Expand Up @@ -30,11 +30,14 @@ Create a new InfoArchive object
// ??? Need loadFile parameter
***********************************************************************************************************************************/
InfoArchive *
infoArchiveNew(const Storage *storage, const String *fileName, bool ignoreMissing)
infoArchiveNew(const Storage *storage, const String *fileName, bool ignoreMissing, CipherType cipherType, const String *cipherPass)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, storage);
FUNCTION_DEBUG_PARAM(STRING, fileName);
FUNCTION_DEBUG_PARAM(BOOL, ignoreMissing);
FUNCTION_DEBUG_PARAM(ENUM, cipherType);
// cipherPass omitted for security

FUNCTION_DEBUG_ASSERT(fileName != NULL);
FUNCTION_DEBUG_END();
Expand All @@ -50,7 +53,7 @@ infoArchiveNew(const Storage *storage, const String *fileName, bool ignoreMissin
// Catch file missing error and add archive-specific hints before rethrowing
TRY_BEGIN()
{
this->infoPg = infoPgNew(storage, fileName, infoPgArchive);
this->infoPg = infoPgNew(storage, fileName, infoPgArchive, cipherType, cipherPass);
}
CATCH(FileMissingError)
{
Expand Down Expand Up @@ -132,6 +135,21 @@ infoArchiveId(const InfoArchive *this)
FUNCTION_TEST_RESULT(STRING, this->archiveId);
}

/***********************************************************************************************************************************
Return the cipher passphrase
***********************************************************************************************************************************/
const String *
infoArchiveCipherPass(const InfoArchive *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INFO_ARCHIVE, this);

FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();

FUNCTION_TEST_RESULT(CONST_STRING, infoPgCipherPass(this->infoPg));
}

/***********************************************************************************************************************************
Get PostgreSQL info
***********************************************************************************************************************************/
Expand Down

0 comments on commit 6c23830

Please sign in to comment.