ENGINE-866: moved bit from key to trust, created set_own_imported_key to replace set_own_key FOR MAIL APPS (does NOT replace it for key reset, as the new function can generate a passphrase error, whereas set_own_key cannot), and did an initial test to ensure the setter/getter functions work on the DB.

Krista Bennett 2 years ago
parent 594133cfde
commit 562239fda8

@ -679,8 +679,7 @@ static PEP_STATUS _create_core_tables(PEP_SESSION session) {
" created integer,\n"
" expires integer,\n"
" comment text,\n"
" flags integer default 0,\n"
" manually_set integer default 0\n"
" flags integer default 0\n"
");\n"
"create index if not exists pgp_keypair_expires on pgp_keypair (\n"
" expires\n"
@ -723,6 +722,7 @@ static PEP_STATUS _create_core_tables(PEP_SESSION session) {
" on delete cascade,\n"
" comm_type integer not null,\n"
" comment text,\n"
" sticky integer default 0,\n"
" primary key (user_id, pgp_keypair_fpr)\n"
");\n"
,
@ -1467,6 +1467,23 @@ static PEP_STATUS _upgrade_DB_to_ver_15(PEP_SESSION session) {
return _create_group_tables(session);
}
static PEP_STATUS _upgrade_DB_to_ver_16(PEP_SESSION session) {
int int_result = sqlite3_exec(
session->db,
"alter table trust\n"
" add column sticky integer default 0;\n",
NULL,
NULL,
NULL
);
assert(int_result == SQLITE_OK);
if (int_result != SQLITE_OK)
return PEP_UNKNOWN_DB_ERROR;
return PEP_STATUS_OK;
}
static PEP_STATUS _check_and_execute_upgrades(PEP_SESSION session, int version) {
PEP_STATUS status = PEP_STATUS_OK;
@ -1526,6 +1543,10 @@ static PEP_STATUS _check_and_execute_upgrades(PEP_SESSION session, int version)
if (status != PEP_STATUS_OK)
return status;
case 15:
status = _upgrade_DB_to_ver_16(session);
if (status != PEP_STATUS_OK)
return status;
case 16:
break;
default:
return PEP_ILLEGAL_VALUE;
@ -1927,7 +1948,22 @@ PEP_STATUS pEp_prepare_sql_stmts(PEP_SESSION session) {
if (int_result != SQLITE_OK)
return PEP_UNKNOWN_DB_ERROR;
int_result = sqlite3_prepare_v2(session->db, sql_set_pgp_keypair_flags,
(int)strlen(sql_set_pgp_keypair_flags), &session->set_pgp_keypair_flags,
NULL);
assert(int_result == SQLITE_OK);
if (int_result != SQLITE_OK)
return PEP_UNKNOWN_DB_ERROR;
int_result = sqlite3_prepare_v2(session->db, sql_unset_pgp_keypair_flags,
(int)strlen(sql_unset_pgp_keypair_flags), &session->unset_pgp_keypair_flags,
NULL);
assert(int_result == SQLITE_OK);
if (int_result != SQLITE_OK)
return PEP_UNKNOWN_DB_ERROR;
int_result = sqlite3_prepare_v2(session->db, sql_set_identity_entry,
(int)strlen(sql_set_identity_entry), &session->set_identity_entry, NULL);
assert(int_result == SQLITE_OK);
@ -2069,6 +2105,23 @@ PEP_STATUS pEp_prepare_sql_stmts(PEP_SESSION session) {
return PEP_UNKNOWN_DB_ERROR;
int_result = sqlite3_prepare_v2(session->db, sql_update_key_sticky_bit_for_user,
(int)strlen(sql_update_key_sticky_bit_for_user),
&session->update_key_sticky_bit_for_user, NULL);
assert(int_result == SQLITE_OK);
if (int_result != SQLITE_OK)
return PEP_UNKNOWN_DB_ERROR;
int_result = sqlite3_prepare_v2(session->db, sql_is_key_sticky_for_user,
(int)strlen(sql_is_key_sticky_for_user),
&session->is_key_sticky_for_user, NULL);
assert(int_result == SQLITE_OK);
if (int_result != SQLITE_OK)
return PEP_UNKNOWN_DB_ERROR;
int_result = sqlite3_prepare_v2(session->db, sql_mark_as_compromised,
(int)strlen(sql_mark_as_compromised), &session->mark_compromised,
NULL);
@ -2503,6 +2556,10 @@ PEP_STATUS pEp_finalize_sql_stmts(PEP_SESSION session) {
sqlite3_finalize(session->get_trust_by_userid);
if (session->least_trust)
sqlite3_finalize(session->least_trust);
if (session->update_key_sticky_bit_for_user)
sqlite3_finalize(session->update_key_sticky_bit_for_user);
if (session->is_key_sticky_for_user)
sqlite3_finalize(session->is_key_sticky_for_user);
if (session->mark_compromised)
sqlite3_finalize(session->mark_compromised);
if (session->crashdump)
@ -2595,6 +2652,10 @@ PEP_STATUS pEp_finalize_sql_stmts(PEP_SESSION session) {
sqlite3_finalize(session->is_invited_group_member);
if (session->is_group_active)
sqlite3_finalize(session->is_group_active);
if (session->set_pgp_keypair_flags)
sqlite3_finalize(session->set_pgp_keypair_flags);
if (session->unset_pgp_keypair_flags)
sqlite3_finalize(session->unset_pgp_keypair_flags);
// retrieve_own_membership_info_for_group_and_ident
// if (session->group_invite_exists)
// sqlite3_finalize(session->group_invite_exists);

@ -3,7 +3,7 @@
#include "pEp_internal.h"
// increment this when patching DDL
#define _DDL_USER_VERSION "15"
#define _DDL_USER_VERSION "16"
PEP_STATUS init_databases(PEP_SESSION session);
PEP_STATUS pEp_sql_init(PEP_SESSION session);
@ -181,7 +181,17 @@ static const char *sql_set_pgp_keypair =
"insert or ignore into pgp_keypair (fpr) "
"values (upper(replace(?1,' ',''))) ;";
static const char *sql_set_pgp_keypair_flags =
"update pgp_keypair set flags = "
" ((?1 & 65535) | (select flags from pgp_keypair "
" where fpr = (upper(replace(?2,' ',''))))) "
" where fpr = (upper(replace(?2,' ',''))) ;";
static const char *sql_unset_pgp_keypair_flags =
"update pgp_keypair set flags = "
" ( ~(?1 & 65535) & (select flags from pgp_keypair"
" where fpr = (upper(replace(?2,' ',''))))) "
" where fpr = (upper(replace(?2,' ',''))) ;";
static const char* sql_exists_identity_entry =
"select count(*) from identity "
@ -336,6 +346,14 @@ static const char *sql_least_trust =
" and comm_type != 0;"; // ignores PEP_ct_unknown
// returns PEP_ct_unknown only when no known trust is recorded
static const char *sql_update_key_sticky_bit_for_user =
"update trust set sticky = ?1 "
" where user_id = ?2 and pgp_keypair_fpr = upper(replace(?3,' ','')) ;";
static const char *sql_is_key_sticky_for_user =
"select sticky from trust "
" where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ','')) ; ";
static const char *sql_mark_as_compromised =
"update trust not indexed set comm_type = 15"
" where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";

@ -2091,6 +2091,58 @@ DYNAMIC_API PEP_STATUS own_keys_retrieve(PEP_SESSION session, stringlist_t **key
return _own_keys_retrieve(session, keylist, 0, true);
}
PEP_STATUS update_key_sticky_bit_for_user(PEP_SESSION session,
pEp_identity* ident,
const char* fpr,
bool sticky) {
if (!session || !ident || EMPTYSTR(ident->user_id) || EMPTYSTR(fpr))
return PEP_ILLEGAL_VALUE;
sqlite3_reset(session->update_key_sticky_bit_for_user);
sqlite3_bind_int(session->update_key_sticky_bit_for_user, 1, sticky);
sqlite3_bind_text(session->update_key_sticky_bit_for_user, 2, ident->user_id, -1,
SQLITE_STATIC);
sqlite3_bind_text(session->update_key_sticky_bit_for_user, 3, fpr, -1,
SQLITE_STATIC);
int result = sqlite3_step(session->update_key_sticky_bit_for_user);
sqlite3_reset(session->update_key_sticky_bit_for_user);
if (result != SQLITE_DONE) {
return PEP_CANNOT_SET_TRUST;
}
return PEP_STATUS_OK;
}
PEP_STATUS get_key_sticky_bit_for_user(PEP_SESSION session,
pEp_identity* ident,
const char* fpr,
bool* is_sticky) {
PEP_STATUS status = PEP_STATUS_OK;
if (!session || !ident || !is_sticky || EMPTYSTR(ident->user_id) || EMPTYSTR(fpr))
return PEP_ILLEGAL_VALUE;
sqlite3_reset(session->is_key_sticky_for_user);
sqlite3_bind_text(session->is_key_sticky_for_user, 1, ident->user_id, -1,
SQLITE_STATIC);
sqlite3_bind_text(session->is_key_sticky_for_user, 2, fpr, -1,
SQLITE_STATIC);
int result = sqlite3_step(session->is_key_sticky_for_user);
switch (result) {
case SQLITE_ROW: {
*is_sticky = sqlite3_column_int(session->is_key_sticky_for_user, 0);
break;
}
default:
status = PEP_KEY_NOT_FOUND;
}
return status;
}
// Returns PASSPHRASE errors when necessary
DYNAMIC_API PEP_STATUS set_own_key(
PEP_SESSION session,
@ -2115,7 +2167,7 @@ DYNAMIC_API PEP_STATUS set_own_key(
// renew if needed, but do not generate
status = _myself(session, me, false, true, true, false);
// we do not need a valid key but dislike other errors
// Pass through invalidity errors, and reject other errors
if (status != PEP_STATUS_OK && status != PEP_GET_KEY_FAILED && status != PEP_KEY_UNSUITABLE)
return status;
status = PEP_STATUS_OK;
@ -2148,6 +2200,39 @@ DYNAMIC_API PEP_STATUS set_own_key(
return status;
}
// This differs from set_own_key because it sets a manually-imported bit in the trust DB
DYNAMIC_API PEP_STATUS set_own_imported_key(
PEP_SESSION session,
pEp_identity* me,
const char* fpr) {
PEP_STATUS status = PEP_STATUS_OK;
assert(session && me);
assert(!EMPTYSTR(fpr));
assert(!EMPTYSTR(me->address));
assert(!EMPTYSTR(me->user_id));
assert(!EMPTYSTR(me->username));
if (!session || !me || EMPTYSTR(fpr) || EMPTYSTR(me->address) ||
EMPTYSTR(me->user_id) || EMPTYSTR(me->username))
return PEP_ILLEGAL_VALUE;
// Last, but not least, be sure we can encrypt with it
status = probe_encrypt(session, fpr);
if (status)
return status;
status = set_own_key(session, me, fpr);
if (status != PEP_STATUS_OK)
return status;
status = update_key_sticky_bit_for_user(session, me, fpr, true);
return status;
}
PEP_STATUS contains_priv_key(PEP_SESSION session, const char *fpr,
bool *has_private) {

@ -460,6 +460,13 @@ DYNAMIC_API PEP_STATUS set_own_key(
const char *fpr
);
DYNAMIC_API PEP_STATUS set_own_imported_key(
PEP_SESSION session,
pEp_identity* me,
const char* fpr
);
//
// clean_own_key_defaults()
//
@ -575,6 +582,12 @@ PEP_STATUS get_valid_pubkey(PEP_SESSION session,
bool* is_address_default,
bool check_blacklist);
PEP_STATUS get_key_sticky_bit_for_user(PEP_SESSION session,
pEp_identity* ident,
const char* fpr,
bool* is_sticky);
#ifdef __cplusplus
}
#endif

@ -2369,24 +2369,6 @@ static void update_encryption_format(identity_list* id_list, PEP_enc_format* enc
}
}
DYNAMIC_API PEP_STATUS probe_encrypt(PEP_SESSION session, const char *fpr)
{
assert(session);
if (!session || EMPTYSTR(fpr))
return PEP_ILLEGAL_VALUE;
stringlist_t *keylist = new_stringlist(fpr);
if (!keylist)
return PEP_OUT_OF_MEMORY;
char *ctext = NULL;
size_t csize = 0;
PEP_STATUS status = encrypt_and_sign(session, keylist, "pEp", 4, &ctext, &csize);
free(ctext);
return status;
}
/**
* @internal
*

@ -694,21 +694,6 @@ PEP_STATUS try_encrypt_message(
PEP_encrypt_flags_t flags
);
/**
* <!-- probe_encrypt() -->
*
* @brief Test if passphrase for a key is working in current session
*
* @param[in] session session handle
* @param[in] fpr fingerprint of key to test
*
* @retval PEP_STATUS_OK in case passphrase works
* @retval error if not
*
*
*/
DYNAMIC_API PEP_STATUS probe_encrypt(PEP_SESSION session, const char *fpr);
#ifdef __cplusplus
}

@ -2661,6 +2661,23 @@ PEP_STATUS sign_only(PEP_SESSION session,
}
DYNAMIC_API PEP_STATUS probe_encrypt(PEP_SESSION session, const char *fpr)
{
assert(session);
if (!session || EMPTYSTR(fpr))
return PEP_ILLEGAL_VALUE;
stringlist_t *keylist = new_stringlist(fpr);
if (!keylist)
return PEP_OUT_OF_MEMORY;
char *ctext = NULL;
size_t csize = 0;
PEP_STATUS status = encrypt_and_sign(session, keylist, "pEp", 4, &ctext, &csize);
free(ctext);
return status;
}
DYNAMIC_API PEP_STATUS verify_text(

@ -510,6 +510,22 @@ DYNAMIC_API PEP_STATUS encrypt_and_sign(
size_t psize, char **ctext, size_t *csize
);
/**
* <!-- probe_encrypt() -->
*
* @brief Test if passphrase for a key is working in current session
*
* @param[in] session session handle
* @param[in] fpr fingerprint of key to test
*
* @retval PEP_STATUS_OK in case passphrase works
* @retval error if not
*
*
*/
DYNAMIC_API PEP_STATUS probe_encrypt(PEP_SESSION session, const char *fpr);
/**
* <!-- set_debug_color() -->
@ -741,11 +757,10 @@ typedef enum _identity_flags {
typedef unsigned int identity_flags_t;
typedef enum _keypair_flags {
PEP_kpf_manually_set = 0x0001;
} keypair_flags;
typedef unsigned int keypair_flags_t;
//typedef enum _keypair_flags {
//} keypair_flags;
//
//typedef unsigned int keypair_flags_t;
/**
* @struct pEp_identity

@ -208,6 +208,8 @@ struct _pEpSession {
// sqlite3_stmt *set_device_group;
// sqlite3_stmt *get_device_group;
sqlite3_stmt *set_pgp_keypair;
sqlite3_stmt *set_pgp_keypair_flags;
sqlite3_stmt *unset_pgp_keypair_flags;
sqlite3_stmt *set_identity_entry;
sqlite3_stmt *update_identity_entry;
sqlite3_stmt *exists_identity_entry;
@ -224,6 +226,8 @@ struct _pEpSession {
sqlite3_stmt *get_trust;
sqlite3_stmt *get_trust_by_userid;
sqlite3_stmt *least_trust;
sqlite3_stmt *update_key_sticky_bit_for_user;
sqlite3_stmt *is_key_sticky_for_user;
sqlite3_stmt *mark_compromised;
sqlite3_stmt *reset_trust;
sqlite3_stmt *crashdump;

@ -0,0 +1,98 @@
#include <stdlib.h>
#include <string>
#include <cstring>
#include "pEpEngine.h"
#include "test_util.h"
#include "TestConstants.h"
#include "Engine.h"
#include <gtest/gtest.h>
namespace {
//The fixture for StickyBitTest
class StickyBitTest : public ::testing::Test {
public:
Engine* engine;
PEP_SESSION session;
protected:
// You can remove any or all of the following functions if its body
// is empty.
StickyBitTest() {
// You can do set-up work for each test here.
test_suite_name = ::testing::UnitTest::GetInstance()->current_test_info()->GTEST_SUITE_SYM();
test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
test_path = get_main_test_home_dir() + "/" + test_suite_name + "/" + test_name;
}
~StickyBitTest() override {
// You can do clean-up work that doesn't throw exceptions here.
}
// If the constructor and destructor are not enough for setting up
// and cleaning up each test, you can define the following methods:
void SetUp() override {
// Code here will be called immediately after the constructor (right
// before each test).
// Leave this empty if there are no files to copy to the home directory path
std::vector<std::pair<std::string, std::string>> init_files = std::vector<std::pair<std::string, std::string>>();
// Get a new test Engine.
engine = new Engine(test_path);
ASSERT_NE(engine, nullptr);
// Ok, let's initialize test directories etc.
engine->prep(NULL, NULL, NULL, init_files);
// Ok, try to start this bugger.
engine->start();
ASSERT_NE(engine->session, nullptr);
session = engine->session;
// Engine is up. Keep on truckin'
}
void TearDown() override {
// Code here will be called immediately after each test (right
// before the destructor).
engine->shut_down();
delete engine;
engine = NULL;
session = NULL;
}
private:
const char* test_suite_name;
const char* test_name;
string test_path;
// Objects declared here can be used by all tests in the StickyBitTest suite.
};
} // namespace
TEST_F(StickyBitTest, check_set_sticky_bit_normal) {
PEP_STATUS status = PEP_STATUS_OK;
ASSERT_TRUE(slurp_and_import_key(session, "test_keys/pub/pep-test-bob-0xC9C2EE39_pub.asc"));
ASSERT_TRUE(slurp_and_import_key(session, "test_keys/priv/pep-test-bob-0xC9C2EE39_priv.asc"));
const char* bob_name = "STOP MESSING WITH ME ALICE";
const char* bob_fpr = "BFCDB7F301DEEEBBF947F29659BFF488C9C2EE39";
pEp_identity* me = new_identity("pep.test.bob@pep-project.org", NULL, PEP_OWN_USERID, bob_name);
status = set_own_imported_key(session, me, bob_fpr);
ASSERT_EQ(status , PEP_STATUS_OK);
status = myself(session, me);
ASSERT_EQ(status , PEP_STATUS_OK);
bool sticky = false;
status = get_key_sticky_bit_for_user(session, me, bob_fpr, &sticky);
ASSERT_TRUE(sticky);
free_identity(me);
}
Loading…
Cancel
Save