-# Copyright (c) 2011 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2011-2020 Samsung Electronics Co., Ltd. All rights reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
STRING(REGEX MATCH "([^.]*)" API_VERSION "${VERSION}")
ADD_DEFINITIONS("-DAPI_VERSION=\"$(API_VERSION)\"")
ADD_DEFINITIONS("-DSMACK_ENABLED")
-ADD_DEFINITIONS("-DSQLCIPHER_HAS_CODEC")
+ADD_DEFINITIONS("-DSQLITE_HAS_CODEC")
+ADD_DEFINITIONS("-DDUMP_LEGACY_DB_LIBNAME=\"${DUMP_LEGACY_DB_LIBNAME}\"")
+ADD_DEFINITIONS("-DLIB_INSTALL_DIR=\"${LIB_INSTALL_DIR}\"")
ADD_DEFINITIONS("-DRUN_DIR=\"${RUN_DIR}\"")
ADD_DEFINITIONS("-DSERVICE_NAME=\"${SERVICE_NAME}\"")
ADD_DEFINITIONS("-DUSER_NAME=\"${USER_NAME}\"")
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(pkgmgr)
BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(sqlcipher)
%if 0%{?watchdog_enabled}
BuildRequires: pkgconfig(argos_watchdog)
%endif
%global initial_values_dir_ro %{ro_data_dir}/initial_values
%global initial_values_dir_rw %{rw_data_dir}/initial_values
%global ca_certs_dir %{?TZ_SYS_CA_CERTS:%TZ_SYS_CA_CERTS}%{!?TZ_SYS_CA_CERTS:%ro_etc_dir/ssl/certs}
+%global dump_legacy_db_libname key-manager-dump-legacy-database
%description
Central Key Manager daemon could be used as secure storage
%if 0%{?sec_build_binary_debug_enable}
export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
- export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
%endif
-# needed to surpress sqlcipher errors while its still embedded
-export CFLAGS="$CFLAGS -Wno-cast-function-type -Wno-implicit-fallthrough"
-export CXXFLAGS="$CXXFLAGS -Wno-cast-function-type -Wno-implicit-fallthrough"
-
-export LDFLAGS+="-Wl,--rpath=%{_libdir},-Bsymbolic-functions "
+export LDFLAGS+="-Wl,--rpath=%{_libdir},-Bsymbolic-functions"
%cmake . -DVERSION=%{version} \
-DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:RELEASE} \
%else
-DTZ_BACKEND_ENABLED=OFF \
%endif
- -DTEST_DIR=%{test_dir}
+ -DTEST_DIR=%{test_dir} \
+ -DDUMP_LEGACY_DB_LIBNAME=%{dump_legacy_db_libname}
make %{?jobs:-j%jobs}
%license LICENSE
%license LICENSE.BSD-3-Clause
%{bin_dir}/key-manager
+%{_libdir}/lib%{dump_legacy_db_libname}.so
%{_unitdir}/multi-user.target.wants/central-key-manager.service
%{_unitdir}/central-key-manager.service
%{_unitdir}/sockets.target.wants/central-key-manager-api-control.socket
cynara-creds-socket
pkgmgr
vconf
+ sqlcipher
${EXTRA_KM_DEPS}
)
FIND_PACKAGE(Threads REQUIRED)
${KEY_MANAGER_PATH}/initial-values/initial-value-loader.cpp
${KEY_MANAGER_PATH}/dpl/db/src/sql_connection.cpp
${KEY_MANAGER_PATH}/dpl/db/src/naive_synchronization_object.cpp
- ${KEY_MANAGER_PATH}/sqlcipher/sqlcipher.c
${KEY_MANAGER_PATH}/crypto/sw-backend/obj.cpp
${KEY_MANAGER_PATH}/crypto/sw-backend/internals.cpp
${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp
${KEY_MANAGER_PATH}/common
${KEY_MANAGER_PATH}/service
${KEY_MANAGER_PATH}/initial-values
- ${KEY_MANAGER_PATH}/sqlcipher
${KEY_MANAGER_PATH}/dpl/core/include
${KEY_MANAGER_PATH}/dpl/log/include
${KEY_MANAGER_PATH}/dpl/db/include
${COMMON_PATH}/dpl/core/include
${COMMON_PATH}/dpl/log/include
${COMMON_PATH}/dpl/db/include
- ${COMMON_PATH}/sqlcipher
${COMMON_PATH}/service
)
INSTALL(TARGETS ${TARGET_KEY_MANAGER_COMMON} DESTINATION ${LIB_INSTALL_DIR})
+
+ADD_SUBDIRECTORY(sqlcipher)
/*
- * Copyright (c) 2014 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#ifndef CKM_SQL_CONNECTION_H
#define CKM_SQL_CONNECTION_H
-#include <dpl/exception.h>
-#include <dpl/availability.h>
#include <memory>
+#include <stdint.h>
+
#include <boost/optional.hpp>
+#include <sqlite3.h>
+
+#include <dpl/availability.h>
+#include <dpl/exception.h>
#include <dpl/log/log.h>
-#include <stdint.h>
#include <dpl/raw-buffer.h>
#include <noncopyable.h>
class DataCommand {
private:
SqlConnection *m_masterConnection;
- sqlcipher3_stmt *m_stmt;
+ sqlite3_stmt *m_stmt;
void CheckBindResult(int result);
void CheckColumnIndex(SqlConnection::ColumnIndex column);
class Flag {
public:
enum Option {
- RO = SQLCIPHER_OPEN_NOMUTEX | SQLCIPHER_OPEN_READONLY,
- RW = SQLCIPHER_OPEN_NOMUTEX | SQLCIPHER_OPEN_READWRITE,
- CRW = RW | SQLCIPHER_OPEN_CREATE
+ RO = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY,
+ RW = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE,
+ CRW = RW | SQLITE_OPEN_CREATE
};
};
// RowID
- typedef sqlcipher3_int64 RowID;
+ typedef sqlite3_int64 RowID;
/**
* Synchronization object used to synchronize SQL connection
};
protected:
- sqlcipher3 *m_connection;
+ sqlite3 *m_connection;
// Options
/**
* Open SQL connection
*
- * Synchronization is archieved by using provided asynchronization object.
+ * Synchronization is achieved by using a provided synchronization object.
* If synchronizationObject is set to NULL, so synchronization is performed.
- * Ownership of the synchronization object is transfered to sql connection
+ * Ownership of the synchronization object is transferred to sql connection
* object.
*
* @param address Database file name
private:
void ExecCommandHelper(Output *out, const char *format, va_list args);
};
+RawBuffer createHexPass(const RawBuffer &rawPass);
} // namespace DB
} // namespace CKM
ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
for (int i = 0; i < MAX_RETRY; i++) {
- int ret = sqlcipher3_prepare_v2(connection->m_connection,
+ int ret = sqlite3_prepare_v2(connection->m_connection,
buffer, strlen(buffer),
&m_stmt, NULL);
- if (ret == SQLCIPHER_OK) {
+ if (ret == SQLITE_OK) {
LogPedantic("Prepared data command: " << buffer);
// Increment stored data command count
++m_masterConnection->m_dataCommandsCount;
return;
- } else if (ret == SQLCIPHER_BUSY) {
+ } else if (ret == SQLITE_BUSY) {
LogPedantic("Collision occurred while preparing SQL command");
// Synchronize if synchronization object is available
}
// Fatal error
- const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
+ const char *error = sqlite3_errmsg(m_masterConnection->m_connection);
LogError("SQL prepare data command failed");
LogError(" Statement: " << buffer);
{
LogPedantic("SQL data command finalizing");
- if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK)
+ if (sqlite3_finalize(m_stmt) != SQLITE_OK)
LogError("Failed to finalize data command");
// Decrement stored data command count
void SqlConnection::DataCommand::CheckBindResult(int result)
{
- if (result != SQLCIPHER_OK) {
- const char *error = sqlcipher3_errmsg(
+ if (result != SQLITE_OK) {
+ const char *error = sqlite3_errmsg(
m_masterConnection->m_connection);
LogError("Failed to bind SQL statement parameter");
void SqlConnection::DataCommand::BindNull(
SqlConnection::ArgumentIndex position)
{
- CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
+ CheckBindResult(sqlite3_bind_null(m_stmt, position));
LogPedantic("SQL data command bind null: ["
<< position << "]");
}
SqlConnection::ArgumentIndex position,
int value)
{
- CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
+ CheckBindResult(sqlite3_bind_int(m_stmt, position, value));
LogPedantic("SQL data command bind integer: ["
<< position << "] -> " << value);
}
SqlConnection::ArgumentIndex position,
int8_t value)
{
- CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
static_cast<int>(value)));
LogPedantic("SQL data command bind int8: ["
<< position << "] -> " << value);
SqlConnection::ArgumentIndex position,
int16_t value)
{
- CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
static_cast<int>(value)));
LogPedantic("SQL data command bind int16: ["
<< position << "] -> " << value);
SqlConnection::ArgumentIndex position,
int32_t value)
{
- CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
static_cast<int>(value)));
LogPedantic("SQL data command bind int32: ["
<< position << "] -> " << value);
SqlConnection::ArgumentIndex position,
int64_t value)
{
- CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
- static_cast<sqlcipher3_int64>(value)));
+ CheckBindResult(sqlite3_bind_int64(m_stmt, position,
+ static_cast<sqlite3_int64>(value)));
LogPedantic("SQL data command bind int64: ["
<< position << "] -> " << value);
}
SqlConnection::ArgumentIndex position,
float value)
{
- CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
+ CheckBindResult(sqlite3_bind_double(m_stmt, position,
static_cast<double>(value)));
LogPedantic("SQL data command bind float: ["
<< position << "] -> " << value);
SqlConnection::ArgumentIndex position,
double value)
{
- CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
+ CheckBindResult(sqlite3_bind_double(m_stmt, position, value));
LogPedantic("SQL data command bind double: ["
<< position << "] -> " << value);
}
}
// Assume that text may disappear
- CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
+ CheckBindResult(sqlite3_bind_text(m_stmt, position,
value, strlen(value),
- SQLCIPHER_TRANSIENT));
+ SQLITE_TRANSIENT));
LogPedantic("SQL data command bind string: ["
<< position << "] -> " << value);
}
// Assume that blob may dissappear
- CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
+ CheckBindResult(sqlite3_bind_blob(m_stmt, position,
raw.data(), raw.size(),
- SQLCIPHER_TRANSIENT));
+ SQLITE_TRANSIENT));
LogPedantic("SQL data command bind blob of size: ["
<< position << "] -> " << raw.size());
}
m_masterConnection->m_synchronizationObject.get());
for (int i = 0; i < MAX_RETRY; i++) {
- int ret = sqlcipher3_step(m_stmt);
+ int ret = sqlite3_step(m_stmt);
- if (ret == SQLCIPHER_ROW) {
+ if (ret == SQLITE_ROW) {
LogPedantic("SQL data command step ROW");
return true;
- } else if (ret == SQLCIPHER_DONE) {
+ } else if (ret == SQLITE_DONE) {
LogPedantic("SQL data command step DONE");
return false;
- } else if (ret == SQLCIPHER_BUSY) {
+ } else if (ret == SQLITE_BUSY) {
LogPedantic("Collision occurred while executing SQL command");
// Synchronize if synchronization object is available
}
// Fatal error
- const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
+ const char *error = sqlite3_errmsg(m_masterConnection->m_connection);
LogError("SQL step data command failed");
LogError(" Error: " << error);
* According to:
* http://www.sqllite.org/c3ref/stmt.html
*
- * if last sqlcipher3_step command on this stmt returned an error,
- * then sqlcipher3_reset will return that error, althought it is not an error.
- * So sqlcipher3_reset allways succedes.
+ * if last sqlite3_step command on this stmt returned an error,
+ * then sqlite3_reset will return that error, althought it is not an error.
+ * So sqlite3_reset allways succedes.
*/
- sqlcipher3_reset(m_stmt);
+ sqlite3_reset(m_stmt);
LogPedantic("SQL data command reset");
}
void SqlConnection::DataCommand::CheckColumnIndex(
SqlConnection::ColumnIndex column)
{
- if (column < 0 || column >= sqlcipher3_column_count(m_stmt))
+ if (column < 0 || column >= sqlite3_column_count(m_stmt))
ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
}
{
LogPedantic("SQL data command get column type: [" << column << "]");
CheckColumnIndex(column);
- return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
+ return sqlite3_column_type(m_stmt, column) == SQLITE_NULL;
}
//LCOV_EXCL_STOP
{
LogPedantic("SQL data command get column integer: [" << column << "]");
CheckColumnIndex(column);
- int value = sqlcipher3_column_int(m_stmt, column);
+ int value = sqlite3_column_int(m_stmt, column);
LogPedantic(" Value: " << value);
return value;
}
{
LogPedantic("SQL data command get column int8: [" << column << "]");
CheckColumnIndex(column);
- int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
+ int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column));
LogPedantic(" Value: " << value);
return value;
}
{
LogPedantic("SQL data command get column int16: [" << column << "]");
CheckColumnIndex(column);
- int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
+ int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column));
LogPedantic(" Value: " << value);
return value;
}
{
LogPedantic("SQL data command get column int32: [" << column << "]");
CheckColumnIndex(column);
- int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
+ int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column));
LogPedantic(" Value: " << value);
return value;
}
{
LogPedantic("SQL data command get column int64: [" << column << "]");
CheckColumnIndex(column);
- int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
+ int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column));
LogPedantic(" Value: " << value);
return value;
}
{
LogPedantic("SQL data command get column float: [" << column << "]");
CheckColumnIndex(column);
- float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
+ float value = static_cast<float>(sqlite3_column_double(m_stmt, column));
LogPedantic(" Value: " << value);
return value;
}
{
LogPedantic("SQL data command get column double: [" << column << "]");
CheckColumnIndex(column);
- double value = sqlcipher3_column_double(m_stmt, column);
+ double value = sqlite3_column_double(m_stmt, column);
LogPedantic(" Value: " << value);
return value;
}
CheckColumnIndex(column);
const char *value = reinterpret_cast<const char *>(
- sqlcipher3_column_text(m_stmt, column));
+ sqlite3_column_text(m_stmt, column));
LogPedantic("Value: " << (value ? value : "NULL"));
CheckColumnIndex(column);
const unsigned char *value = reinterpret_cast<const unsigned char *>(
- sqlcipher3_column_blob(m_stmt, column));
+ sqlite3_column_blob(m_stmt, column));
if (value == NULL)
return RawBuffer();
- int length = sqlcipher3_column_bytes(m_stmt, column);
+ int length = sqlite3_column_bytes(m_stmt, column);
LogPedantic("Got blob of length: " << length);
return RawBuffer(value, value + length);
<< column << "]");
CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
return boost::optional<int>();
- int value = sqlcipher3_column_int(m_stmt, column);
+ int value = sqlite3_column_int(m_stmt, column);
LogPedantic(" Value: " << value);
return boost::optional<int>(value);
}
<< column << "]");
CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
return boost::optional<int8_t>();
- int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
+ int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column));
LogPedantic(" Value: " << value);
return boost::optional<int8_t>(value);
}
<< column << "]");
CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
return boost::optional<int16_t>();
- int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
+ int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column));
LogPedantic(" Value: " << value);
return boost::optional<int16_t>(value);
}
<< column << "]");
CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
return boost::optional<int32_t>();
- int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
+ int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column));
LogPedantic(" Value: " << value);
return boost::optional<int32_t>(value);
}
<< column << "]");
CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
return boost::optional<int64_t>();
- int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
+ int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column));
LogPedantic(" Value: " << value);
return boost::optional<int64_t>(value);
}
<< column << "]");
CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
return boost::optional<float>();
- float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
+ float value = static_cast<float>(sqlite3_column_double(m_stmt, column));
LogPedantic(" Value: " << value);
return boost::optional<float>(value);
}
<< column << "]");
CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
return boost::optional<double>();
- double value = sqlcipher3_column_double(m_stmt, column);
+ double value = sqlite3_column_double(m_stmt, column);
LogPedantic(" Value: " << value);
return boost::optional<double>(value);
}
LogPedantic("SQL data command get column blog: [" << column << "]");
CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
return boost::optional<RawBuffer>();
const unsigned char *value = reinterpret_cast<const unsigned char *>(
- sqlcipher3_column_blob(m_stmt, column));
+ sqlite3_column_blob(m_stmt, column));
- int length = sqlcipher3_column_bytes(m_stmt, column);
+ int length = sqlite3_column_bytes(m_stmt, column);
LogPedantic("Got blob of length: " << length);
RawBuffer temp(value, value + length);
// Connect to database
int result;
- result = sqlcipher3_open_v2(
+ result = sqlite3_open_v2(
address.c_str(),
&m_connection,
flag,
NULL);
- if (result == SQLCIPHER_OK) {
+ if (result == SQLITE_OK) {
LogPedantic("Connected to DB");
} else {
LogError("Failed to connect to DB!");
TurnOnForeignKeys();
}
-const std::string SQLCIPHER_RAW_PREFIX = "x'";
-const std::string SQLCIPHER_RAW_SUFIX = "'";
-const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
+const std::string SQLITE_RAW_PREFIX = "x'";
+const std::string SQLITE_RAW_SUFIX = "'";
+const std::size_t SQLITE_RAW_DATA_SIZE = 32;
RawBuffer rawToHexString(const RawBuffer &raw)
{
// We are required to pass 64byte long hex password made out of 32byte raw
// binary data
RawBuffer output;
- std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
+ std::copy(SQLITE_RAW_PREFIX.begin(), SQLITE_RAW_PREFIX.end(),
std::back_inserter(output));
RawBuffer password = rawToHexString(rawPass);
std::copy(password.begin(), password.end(),
std::back_inserter(output));
- std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
+ std::copy(SQLITE_RAW_SUFIX.begin(), SQLITE_RAW_SUFIX.end(),
std::back_inserter(output));
return output;
return;
}
- if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
+ if (rawPass.size() != SQLITE_RAW_DATA_SIZE)
ThrowMsg(Exception::InvalidArguments,
"Binary data for raw password should be 32 bytes long.");
RawBuffer pass = createHexPass(rawPass);
- int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
+ int result = sqlite3_key(m_connection, pass.data(), pass.size());
- if (result == SQLCIPHER_OK) {
+ if (result == SQLITE_OK) {
LogPedantic("Set key on DB");
} else {
- //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
+ //sqlite3_key fails only when m_connection == NULL || key == NULL ||
// key length == 0
LogError("Failed to set key on DB");
ThrowMsg(Exception::InvalidArguments, result);
}
// Binary data for raw password should be 32 bytes long.
- assert(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
- rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE);
+ assert(rawPassOld.size() == SQLITE_RAW_DATA_SIZE &&
+ rawPassNew.size() == SQLITE_RAW_DATA_SIZE);
-
- // sqlcipher3_rekey requires for key to be already set
+ // sqlite3_rekey requires for key to be already set
if (!m_isKeySet)
SetKey(rawPassOld);
RawBuffer pass = createHexPass(rawPassNew);
- int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
+ int result = sqlite3_rekey(m_connection, pass.data(), pass.size());
- if (result == SQLCIPHER_OK) {
+ if (result == SQLITE_OK) {
LogPedantic("Reset key on DB");
} else {
- //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
+ //sqlite3_rekey fails only when m_connection == NULL || key == NULL ||
// key length == 0
LogError("Failed to reset key on DB");
ThrowMsg(Exception::InvalidArguments, result);
int result;
- result = sqlcipher3_close(m_connection);
+ result = sqlite3_close(m_connection);
- if (result != SQLCIPHER_OK) {
- const char *error = sqlcipher3_errmsg(m_connection);
+ if (result != SQLITE_OK) {
+ const char *error = sqlite3_errmsg(m_connection);
LogError("SQL close failed");
LogError(" Error: " << error);
Throw(Exception::InternalError);
}
DataCommandUniquePtr command =
- PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
+ PrepareDataCommand("select tbl_name from sqlite_master where name=?;");
command->BindString(1, tableName);
for (int i = 0; i < MAX_RETRY; i++) {
char *errorBuffer;
- int ret = sqlcipher3_exec(m_connection,
+ int ret = sqlite3_exec(m_connection,
queryPtr.get(),
out ? &Output::Callback : NULL,
out,
// Take allocated error buffer
if (errorBuffer != NULL) {
errorMsg = errorBuffer;
- sqlcipher3_free(errorBuffer);
+ sqlite3_free(errorBuffer);
}
- if (ret == SQLCIPHER_OK)
+ if (ret == SQLITE_OK)
return;
- if (ret == SQLCIPHER_BUSY) {
+ if (ret == SQLITE_BUSY) {
LogPedantic("Collision occurred while executing SQL command");
// Synchronize if synchronization object is available
//LCOV_EXCL_START
SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
{
- return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
+ return static_cast<RowID>(sqlite3_last_insert_rowid(m_connection));
}
//LCOV_EXCL_STOP
RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
- handle.database = DB::Crypto(fs.getDBPath(), key);
+ handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
handle.crypto = CryptoLogic();
if (!m_accessControl.isSystemService(user)) {
* @brief Implementation of encrypted db access layer
*/
+#include <dlfcn.h>
+#include <fcntl.h>
#include <fstream>
+#include <libgen.h>
+#include <sys/stat.h>
#include <db-crypto.h>
#include <dpl/db/sql_connection.h>
+#include <dpl/errno_string.h>
#include <dpl/log/log.h>
+#include <dpl/scoped_ptr.h>
#include <ckm/ckm-error.h>
#include <exception.h>
namespace CKM {
namespace DB {
-Crypto::Crypto(const std::string &path, const RawBuffer &rawPass) :
+
+namespace {
+auto openSqlConnection(const std::string &path, const RawBuffer &rawPass)
+{
+ auto conn = std::make_unique<SqlConnection>(path, SqlConnection::Flag::Option::CRW);
+ conn->SetKey(rawPass);
+ return conn;
+}
+
+void convertLegacyDatabase(const std::string &legacyPath, const std::string &path, const RawBuffer &rawPass)
+{
+ {
+ struct stat st;
+ if (lstat(legacyPath.c_str(), &st)) {
+ const auto err = errno;
+ if (ENOENT != err)
+ ThrowErr(Exc::DatabaseFailed, "lstat failed: " << GetErrnoString(err));
+ LogDebug("legacy db does not exist, proceeding");
+ return;
+ }
+ if (!S_ISREG(st.st_mode))
+ ThrowErr(Exc::DatabaseFailed, "legacy db not a regular file");
+ }
+ if (unlink(path.c_str()) && ENOENT != errno)
+ ThrowErr(Exc::DatabaseFailed, "unlink failed: " << GetErrnoString());
+
+ // in no way to I condone the use of unique_ptr in this context; see: review
+ struct Dlclose { void operator()(void *p) { dlclose(p); } };
+ const auto handle = std::unique_ptr<void, Dlclose>(
+ dlopen(LIB_INSTALL_DIR "/lib" DUMP_LEGACY_DB_LIBNAME ".so", RTLD_LAZY)
+ ?: ThrowErr(Exc::DatabaseFailed, "dlopen failed: " << dlerror()));
+ const auto dumpLegacyDb = (char *(*)(const char *, const unsigned char *, size_t))
+ dlsym(handle.get(), "dumpLegacyDb")
+ ?: ThrowErr(Exc::DatabaseFailed, "dlsym failed: " << dlerror());
+
+ {
+ const RawBuffer pass = createHexPass(rawPass);
+ const CharUniquePtr sqlDump(dumpLegacyDb(legacyPath.c_str(), pass.data(), pass.size())
+ ?: ThrowErr(Exc::DatabaseFailed, "dump failed"));
+
+ // close to ensure full sync regardless of pragma synchronous value
+ // EXTRA is needed to sync the dir after transaction but isn't used in ckm
+ openSqlConnection(path, rawPass)->ExecCommand(sqlDump.get());
+ LogDebug("legacy db converted, removing");
+ }
+
+ if (unlink(legacyPath.c_str()))
+ ThrowErr(Exc::DatabaseFailed, "unlink legacy db failed: " << GetErrnoString());
+ std::string legacyPathCopy(legacyPath);
+ const auto legacyDirPath = dirname(&legacyPathCopy[0]);
+ const int legacyDirFd = TEMP_FAILURE_RETRY(open(legacyDirPath, O_RDONLY));
+ if (legacyDirFd < 0)
+ ThrowErr(Exc::DatabaseFailed, "open failed: " << GetErrnoString());
+ const auto fsyncRes = fsync(legacyDirFd);
+ const auto fsyncErrno = errno;
+ close(legacyDirFd);
+ if (fsyncRes)
+ ThrowErr(Exc::DatabaseFailed, "fsync failed: " << GetErrnoString(fsyncErrno));
+}
+} // namespace
+
+Crypto::Crypto(const std::string &legacyPath, const std::string &path, const RawBuffer &rawPass) :
m_inUserTransaction(false)
{
try {
- m_connection.reset(new SqlConnection(path, SqlConnection::Flag::Option::CRW));
- m_connection->SetKey(rawPass);
+ convertLegacyDatabase(legacyPath, path, rawPass);
+ m_connection = openSqlConnection(path, rawPass);
initDatabase();
m_connection->ExecCommand("VACUUM;");
} catch (const SqlConnection::Exception::ConnectionBroken &e) {
{
// run migration if old database is present
int schemaVersion;
-
- if (getDBVersion(schemaVersion) == false || // DB empty or corrupted
- schemaVersion > DB_VERSION_CURRENT) { // or too new scheme
+ if (!getDBVersion(schemaVersion) || schemaVersion > DB_VERSION_CURRENT) {
LogDebug("no database or database corrupted, initializing the DB");
- resetDB();
- } else {
+ goto fail;
+ }
+ if (schemaVersion < DB_VERSION_CURRENT) {
// migration needed
LogDebug("DB migration from version " << schemaVersion << " to version " <<
DB_VERSION_CURRENT << " started.");
if (!script) {
LogError("Error, script to migrate database from version: " << vi <<
" to version: " << vi + 1 << " not available, resetting the DB");
- resetDB();
- break;
+ goto fail;
}
LogInfo("migrating from version " << vi << " to version " << vi + 1);
- m_connection->ExecCommand((*script).c_str());
+ m_connection->ExecCommand(script->c_str());
}
// update DB version info
SchemaInfo.setVersionInfo();
transaction.commit();
}
+ return;
+
+fail:
+ resetDB();
}
Crypto::ScriptOptional Crypto::getScript(const std::string &scriptName) const
Crypto() : m_inUserTransaction(false) {}
// user name instead of path?
- Crypto(const std::string &path, const RawBuffer &rawPass);
+ // in no way to I condone the use of std::string for legacyPath; see: review
+ Crypto(const std::string &legacyPath, const std::string &path, const RawBuffer &rawPass);
Crypto(const Crypto &other) = delete;
Crypto(Crypto &&other);
#include <for-each-file.h>
#include <file-system.h>
+namespace CKM {
+
namespace {
const std::string CKM_KEY_PREFIX = "key-";
const std::string CKM_DB_KEY_PREFIX = "db-key-";
-const std::string CKM_DB_PREFIX = "db-";
+const std::string CKM_LEGACY_DB_PREFIX = "db-";
+const std::string CKM_DB_PREFIX = "db0-";
const std::string CKM_REMOVED_APP_PREFIX = "removed-app-";
const std::string CKM_LOCK_FILE = RUN_DIR "/" SERVICE_NAME "/key-manager.pid";
-} // namespace anonymous
+wur std::string getPath(const std::string &prefix, uid_t uid)
+{
+ std::stringstream ss;
+ ss << RW_DATA_DIR << "/" << prefix << uid;
+ return ss.str();
+}
-namespace CKM {
+} // namespace anonymous
FileSystem::FileSystem(uid_t uid)
: m_uid(uid)
{
}
+std::string FileSystem::getLegacyDBPath() const
+{
+ return getPath(CKM_LEGACY_DB_PREFIX, m_uid);
+}
+
std::string FileSystem::getDBPath() const
{
- std::stringstream ss;
- ss << RW_DATA_DIR << "/" << CKM_DB_PREFIX << m_uid;
- return ss.str();
+ return getPath(CKM_DB_PREFIX, m_uid);
}
std::string FileSystem::getDKEKPath() const
{
- std::stringstream ss;
- ss << RW_DATA_DIR << "/" << CKM_KEY_PREFIX << m_uid;
- return ss.str();
+ return getPath(CKM_KEY_PREFIX, m_uid);
}
std::string FileSystem::getDBDEKPath() const
{
- std::stringstream ss;
- ss << RW_DATA_DIR << "/" << CKM_DB_KEY_PREFIX << m_uid;
- return ss.str();
+ return getPath(CKM_DB_KEY_PREFIX, m_uid);
}
std::string FileSystem::getRemovedAppsPath() const
{
- std::stringstream ss;
- ss << RW_DATA_DIR << "/" << CKM_REMOVED_APP_PREFIX << m_uid;
- return ss.str();
+ return getPath(CKM_REMOVED_APP_PREFIX, m_uid);
}
RawBuffer FileSystem::loadFile(const std::string &path) const
};
return unlinkUserPath(getDBPath(), " database")
+ | unlinkUserPath(getLegacyDBPath(), " legacy database")
| unlinkUserPath(getDKEKPath(), " DKEK")
| unlinkUserPath(getDBDEKPath(), " DBDEK")
| unlinkUserPath(getRemovedAppsPath(), "'s Removed Apps File");
public:
explicit FileSystem(uid_t uid);
+ wur std::string getLegacyDBPath() const;
wur std::string getDBPath() const;
// Domain Key Encryption Key
--- /dev/null
+# Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ADD_LIBRARY(
+ ${DUMP_LEGACY_DB_LIBNAME}
+ SHARED
+ sqlcipher.c
+)
+
+SET_TARGET_PROPERTIES(
+ ${DUMP_LEGACY_DB_LIBNAME}
+ PROPERTIES
+ COMPILE_FLAGS "-fvisibility=hidden -Wl,--no-undefined"
+)
+
+INSTALL(
+ TARGETS
+ ${DUMP_LEGACY_DB_LIBNAME}
+ DESTINATION
+ ${LIB_INSTALL_DIR}
+)
** language. The code for the "sqlite3" command-line shell is also in a
** separate file. This file contains only code for the core SQLite library.
*/
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
#ifndef SQLITE_PRIVATE
** is a special table that holds the names and attributes of all
** user tables and indices.
*/
-#define MASTER_NAME "sqlite_master"
-#define TEMP_MASTER_NAME "sqlite_temp_master"
+#define MASTER_NAME "sqlcipher_master"
+#define TEMP_MASTER_NAME "sqlcipher_temp_master"
/*
** The root-page of the master database table.
*/
zSql = sqlite3_mprintf(
"SELECT sql "
- " FROM %s.sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
+ " FROM %s.sqlcipher_master WHERE type='table' AND name!='sqlcipher_sequence'"
" AND rootpage>0"
, sourceDb);
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
zSql = sqlite3_mprintf(
"SELECT sql "
- " FROM %s.sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
+ " FROM %s.sqlcipher_master WHERE sql LIKE 'CREATE INDEX %%' "
, sourceDb);
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
if( rc!=SQLITE_OK ) goto end_of_export;
zSql = sqlite3_mprintf(
"SELECT sql "
- " FROM %s.sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
+ " FROM %s.sqlcipher_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
, sourceDb);
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
if( rc!=SQLITE_OK ) goto end_of_export;
zSql = sqlite3_mprintf(
"SELECT 'INSERT INTO %s.' || quote(name) "
"|| ' SELECT * FROM %s.' || quote(name) || ';'"
- "FROM %s.sqlite_master "
- "WHERE type = 'table' AND name!='sqlite_sequence' "
+ "FROM %s.sqlcipher_master "
+ "WHERE type = 'table' AND name!='sqlcipher_sequence' "
" AND rootpage>0"
, targetDb, sourceDb, sourceDb);
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
zSql = sqlite3_mprintf(
"SELECT 'INSERT INTO %s.' || quote(name) "
"|| ' SELECT * FROM %s.' || quote(name) || ';' "
- "FROM %s.sqlite_master WHERE name=='sqlite_sequence';"
+ "FROM %s.sqlcipher_master WHERE name=='sqlcipher_sequence';"
, targetDb, sourceDb, targetDb);
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
if( rc!=SQLITE_OK ) goto end_of_export;
** from the SQLITE_MASTER table.
*/
zSql = sqlite3_mprintf(
- "INSERT INTO %s.sqlite_master "
+ "INSERT INTO %s.sqlcipher_master "
" SELECT type, name, tbl_name, rootpage, sql"
- " FROM %s.sqlite_master"
+ " FROM %s.sqlcipher_master"
" WHERE type='view' OR type='trigger'"
" OR (type='table' AND rootpage=0)"
, targetDb, sourceDb);
openssl_init_count--;
if(openssl_init_count == 0) {
- sqlite3_mutex *temp_mutex;
if(openssl_external_init == 0) {
/* if OpenSSL hasn't be initialized externally, and the counter reaches zero
after it's decremented, release EVP memory
CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
return aData;
}
-
-/*
-** Return the current pager state
-*/
-SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
- return pPager->eState;
-}
#endif /* SQLITE_HAS_CODEC */
#ifndef SQLITE_OMIT_AUTOVACUUM
"WHEN type='table' THEN %Q "
"WHEN name LIKE 'sqliteX_autoindex%%' ESCAPE 'X' "
" AND type='index' THEN "
- "'sqlite_autoindex_' || %Q || substr(name,%d+18) "
+ "'sqlcipher_autoindex_' || %Q || substr(name,%d+18) "
"ELSE name END "
"WHERE tbl_name=%Q COLLATE nocase AND "
"(type='table' OR type='index' OR type='trigger');",
/* If the sqlite_sequence table exists in this database, then update
** it with the new table name.
*/
- if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
+ if( sqlite3FindTable(db, "sqlcipher_sequence", zDb) ){
sqlite3NestedParse(pParse,
- "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q",
+ "UPDATE \"%w\".sqlcipher_sequence set name = %Q WHERE name = %Q",
zDb, zName, pTab->zName);
}
#endif
** as required. */
if( iDb!=1 ){
sqlite3NestedParse(pParse,
- "UPDATE sqlite_temp_master SET "
+ "UPDATE sqlcipher_temp_master SET "
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
"tbl_name = "
"CASE WHEN tbl_name=%Q COLLATE nocase AND "
const char *zName;
const char *zCols;
} aTable[] = {
- { "sqlite_stat1", "tbl,idx,stat" },
+ { "sqlcipher_stat1", "tbl,idx,stat" },
#if defined(SQLITE_ENABLE_STAT4)
- { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
+ { "sqlcipher_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
#else
- { "sqlite_stat4", 0 },
+ { "sqlcipher_stat4", 0 },
#endif
- { "sqlite_stat3", 0 },
+ { "sqlcipher_stat3", 0 },
};
int i;
sqlite3 *db = pParse->db;
pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13);
if( pStat1==0 ) return;
pStat1->zName = (char*)&pStat1[1];
- memcpy(pStat1->zName, "sqlite_stat1", 13);
+ memcpy(pStat1->zName, "sqlcipher_stat1", 16);
pStat1->nCol = 3;
pStat1->iPKey = -1;
sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
int rc = SQLITE_OK; /* Result codes from subroutines */
assert( db->lookaside.bDisable );
- if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
+ if( sqlite3FindTable(db, "sqlcipher_stat4", zDb) ){
rc = loadStatTbl(db,
- "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
- "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
+ "SELECT idx,count(*) FROM %Q.sqlcipher_stat4 GROUP BY idx",
+ "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlcipher_stat4",
zDb
);
}
/* Load new statistics out of the sqlite_stat1 table */
sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zDbSName;
- if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
+ if( sqlite3FindTable(db, "sqlcipher_stat1", sInfo.zDatabase)!=0 ){
zSql = sqlite3MPrintf(db,
- "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
+ "SELECT tbl,idx,stat FROM %Q.sqlcipher_stat1", sInfo.zDatabase);
if( zSql==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
** so that INSERT can find the table easily.
*/
#ifndef SQLITE_OMIT_AUTOINCREMENT
- if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
+ if( !pParse->nested && strcmp(zName, "sqlcipher_sequence")==0 ){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pTable->pSchema->pSeqTab = pTable;
}
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( pDb->pSchema->pSeqTab==0 ){
sqlite3NestedParse(pParse,
- "CREATE TABLE %Q.sqlite_sequence(name,seq)",
+ "CREATE TABLE %Q.sqlcipher_sequence(name,seq)",
pDb->zDbSName
);
}
const char *zDbName = pParse->db->aDb[iDb].zDbSName;
for(i=1; i<=4; i++){
char zTab[24];
- sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
+ sqlite3_snprintf(sizeof(zTab),zTab,"sqlcipher_stat%d",i);
if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE %s=%Q",
*/
if( pTab->tabFlags & TF_Autoincrement ){
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.sqlite_sequence WHERE name=%Q",
+ "DELETE FROM %Q.sqlcipher_sequence WHERE name=%Q",
pDb->zDbSName, pTab->zName
);
}
int n;
Index *pLoop;
for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
- zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n);
+ zName = sqlite3MPrintf(db, "sqlcipher_autoindex_%s_%d", pTab->zName, n);
if( zName==0 ){
goto exit_create_index;
}
u8 p5 = 0;
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
- if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){
+ if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlcipher_stat1") ){
sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
}
if( eMode!=ONEPASS_OFF ){
if( pPragma->iArg==2 || pPragma->iArg==3 ){
u8 iByte;
int i;
- for(i=0, iByte=0; i<sizeof(zBuf)*2 && sqlite3Isxdigit(zRight[i]); i++){
+ for(i=0, iByte=0; i<(int)(sizeof(zBuf)*2) && sqlite3Isxdigit(zRight[i]); i++){
iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
if( (i&1)!=0 ) zBuf[i/2] = iByte;
}
*/
db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
rc = execSqlF(db, pzErrMsg,
- "SELECT sql FROM \"%w\".sqlite_master"
- " WHERE type='table'AND name<>'sqlite_sequence'"
+ "SELECT sql FROM \"%w\".sqlcipher_master"
+ " WHERE type='table'AND name<>'sqlcipher_sequence'"
" AND coalesce(rootpage,1)>0",
zDbMain
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execSqlF(db, pzErrMsg,
- "SELECT sql FROM \"%w\".sqlite_master"
+ "SELECT sql FROM \"%w\".sqlcipher_master"
" WHERE type='index'",
zDbMain
);
rc = execSqlF(db, pzErrMsg,
"SELECT'INSERT INTO vacuum_db.'||quote(name)"
"||' SELECT*FROM\"%w\".'||quote(name)"
- "FROM vacuum_db.sqlite_master "
+ "FROM vacuum_db.sqlcipher_master "
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbMain
);
** from the SQLITE_MASTER table.
*/
rc = execSqlF(db, pzErrMsg,
- "INSERT INTO vacuum_db.sqlite_master"
- " SELECT*FROM \"%w\".sqlite_master"
+ "INSERT INTO vacuum_db.sqlcipher_master"
+ " SELECT*FROM \"%w\".sqlcipher_master"
" WHERE type IN('view','trigger')"
" OR(type='table'AND rootpage=0)",
zDbMain
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
const char *zName;
if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
- if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){
+ if( strncmp(zName, "sqlcipher_autoindex_", 20)==0 ){
int i = sqlite3Strlen30(zName) - 1;
while( zName[i]!='_' ) i--;
zName += i;
u8 iByte;
int i;
char zDecoded[40];
- for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
+ for(i=0, iByte=0; i<(int)(sizeof(zDecoded)*2) && sqlite3Isxdigit(zKey[i]); i++){
iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
if( (i&1)!=0 ) zDecoded[i/2] = iByte;
}
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
*/
static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
- const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
+ const char *zFmt = "SELECT stat FROM %Q.sqlcipher_stat1 WHERE tbl = '%q_rowid'";
char *zSql;
sqlite3_stmt *p;
int rc;
i64 nRow = 0;
rc = sqlite3_table_column_metadata(
- db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
+ db, pRtree->zDb, "sqlcipher_stat1",0,0,0,0,0,0
);
if( rc!=SQLITE_OK ){
pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
sqlite3_mprintf(
"SELECT rbu_target_name(name, type='view') AS target, name "
- "FROM sqlite_master "
+ "FROM sqlcipher_master "
"WHERE type IN ('table', 'view') AND target IS NOT NULL "
" %s "
"ORDER BY name"
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
"SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
- " FROM main.sqlite_master "
+ " FROM main.sqlcipher_master "
" WHERE type='index' AND tbl_name = ?"
);
}
p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
sqlite3_mprintf(
"SELECT (sql LIKE 'create virtual%%'), rootpage"
- " FROM sqlite_master"
+ " FROM sqlcipher_master"
" WHERE name=%Q", zTab
));
if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){
if( zOrig && zIdx && zOrig[0]=='p' ){
p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
sqlite3_mprintf(
- "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx
+ "SELECT rootpage FROM sqlcipher_master WHERE name = %Q", zIdx
));
if( p->rc==SQLITE_OK ){
if( sqlite3_step(aStmt[2])==SQLITE_ROW ){
** This is needed for the argument to "PRAGMA index_xinfo". Set
** zIdx to point to a nul-terminated string containing this name. */
p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
- "SELECT name FROM sqlite_master WHERE rootpage = ?"
+ "SELECT name FROM sqlcipher_master WHERE rootpage = ?"
);
if( p->rc==SQLITE_OK ){
sqlite3_bind_int(pQuery, 1, tnum);
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
- "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?"
+ "SELECT trim(sql) FROM sqlcipher_master WHERE type='index' AND name=?"
);
}
if( rc==SQLITE_OK ){
int bOk = 0;
sqlite3_stmt *pCnt = 0;
p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
- "SELECT count(*) FROM stat.sqlite_master"
+ "SELECT count(*) FROM stat.sqlcipher_master"
);
if( p->rc==SQLITE_OK
&& sqlite3_step(pCnt)==SQLITE_ROW
if( p->rc==SQLITE_OK ){
p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
}
- rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
+ rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlcipher_master");
/* Mark the database file just opened as an RBU target database. If
** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use.
if( pState==0 ){
p->eStage = 0;
if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0);
+ p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlcipher_master", 0, 0, 0);
}
}
p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
- " AND name!='sqlite_sequence' "
+ "SELECT sql FROM sqlcipher_master WHERE sql!='' AND rootpage!=0"
+ " AND name!='sqlcipher_sequence' "
" ORDER BY type DESC"
);
}
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
+ "SELECT * FROM sqlcipher_master WHERE rootpage=0 OR rootpage IS NULL"
);
}
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
- "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+ "INSERT INTO sqlcipher_master VALUES(?,?,?,?,?)"
);
}
assert( nVal==1 );
rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
- sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
+ sqlite3_mprintf("SELECT count(*) FROM sqlcipher_master "
"WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
);
if( rc!=SQLITE_OK ){
** occurs, nPhaseOneStep will be left set to -1. */
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
+ "SELECT 1 FROM sqlcipher_master WHERE tbl_name = 'rbu_count'"
);
}
if( p->rc==SQLITE_OK ){
sqlite3_finalize(pCsr->pStmt);
pCsr->pStmt = 0;
zSql = sqlite3_mprintf(
- "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
+ "SELECT 'sqlcipher_master' AS name, 1 AS rootpage, 'table' AS type"
" UNION ALL "
"SELECT name, rootpage, type"
- " FROM \"%w\".sqlite_master WHERE rootpage!=0"
+ " FROM \"%w\".sqlcipher_master WHERE rootpage!=0"
" ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName);
if( zSql==0 ){
return SQLITE_NOMEM_BKPT;
assert( pazCol && pabPK );
nThis = sqlite3Strlen30(zThis);
- if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
+ if( nThis==12 && 0==sqlite3_stricmp("sqlcipher_stat1", zThis) ){
rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
if( rc==SQLITE_OK ){
/* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
break;
}
}
- if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
+ if( 0==sqlite3_stricmp("sqlcipher_stat1", pTab->zName) ){
pTab->bStat1 = 1;
}
}
if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
zSql = sqlite3_mprintf(
- "SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
+ "SELECT tbl, ?2, stat FROM %Q.sqlcipher_stat1 WHERE tbl IS ?1 AND "
"idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
);
if( zSql==0 ) rc = SQLITE_NOMEM;
** other tables.
*/
static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
- int rc = sessionSelectRow(db, "sqlite_stat1", p);
+ int rc = sessionSelectRow(db, "sqlcipher_stat1", p);
if( rc==SQLITE_OK ){
rc = sessionPrepare(db, &p->pInsert,
- "INSERT INTO main.sqlite_stat1 VALUES(?1, "
+ "INSERT INTO main.sqlcipher_stat1 VALUES(?1, "
"CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, "
"?3)"
);
}
if( rc==SQLITE_OK ){
rc = sessionPrepare(db, &p->pUpdate,
- "UPDATE main.sqlite_stat1 SET "
+ "UPDATE main.sqlcipher_stat1 SET "
"tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
"idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
"stat = CASE WHEN ?8 THEN ?9 ELSE stat END "
}
if( rc==SQLITE_OK ){
rc = sessionPrepare(db, &p->pDelete,
- "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
+ "DELETE FROM main.sqlcipher_stat1 WHERE tbl=?1 AND idx IS "
"CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END "
"AND (?4 OR stat IS ?3)"
);
}
else{
sApply.nCol = nCol;
- if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){
+ if( 0==sqlite3_stricmp(zTab, "sqlcipher_stat1") ){
if( (rc = sessionStat1Sql(db, &sApply) ) ){
break;
}
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
/************************** End of sqlite3.c ******************************/
+#pragma GCC diagnostic pop
/************** Begin file dbdump.c ********************************************/
/*
** 2016-03-13
** of the database file, the schema, and optionally the table, forming the
** first three arguments of a single call to the library routine.
*/
-#include "sqlite3.h"
-#include <stdarg.h>
-#include <string.h>
#include <ctype.h>
/*
zType = azArg[1];
zSql = azArg[2];
- if( strcmp(zTable, "sqlite_sequence")==0 ){
+ if( strcmp(zTable, "sqlcipher_sequence")==0 ){
p->xCallback("DELETE FROM sqlite_sequence;\n", p->pArg);
- }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
+ }else if( sqlite3_strglob("sqlcipher_stat?", zTable)==0 ){
p->xCallback("ANALYZE sqlite_master;\n", p->pArg);
- }else if( strncmp(zTable, "sqlite_", 7)==0 ){
+ }else if( strncmp(zTable, "sqlcipher_", 10)==0 ){
return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
if( !p->writableSchema ){
/* Always quote the table name, even if it appears to be pure ascii,
** in case it is a keyword. Ex: INSERT INTO "table" ... */
- appendText(&sTable, zTable, quoteChar(zTable));
+ if (strncmp(zTable, "sqlcipher_", sizeof "sqlcipher"))
+ appendText(&sTable, zTable, quoteChar(zTable));
+ else {
+ appendText(&sTable, "sqlite_", 0);
+ appendText(&sTable, zTable + sizeof "sqlcipher", 0);
+ }
/* If preserving the rowid, add a column list after the table name.
** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
*/
int sqlite3_db_dump(
sqlite3 *db, /* The database connection */
- const char *zSchema, /* Which schema to dump. Usually "main". */
- const char *zTable, /* Which table to dump. NULL means everything. */
int (*xCallback)(const char*,void*), /* Output sent to this callback */
void *pArg /* Second argument of the callback */
){
x.xCallback = xCallback;
x.pArg = pArg;
xCallback("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n", pArg);
- if( zTable==0 ){
- run_schema_dump_query(&x,
- "SELECT name, type, sql FROM \"%w\".sqlite_master "
- "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'",
- zSchema
- );
- run_schema_dump_query(&x,
- "SELECT name, type, sql FROM \"%w\".sqlite_master "
- "WHERE name=='sqlite_sequence'", zSchema
- );
- output_sql_from_query(&x,
- "SELECT sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
- );
- }else{
- run_schema_dump_query(&x,
- "SELECT name, type, sql FROM \"%w\".sqlite_master "
- "WHERE tbl_name=%Q COLLATE nocase AND type=='table'"
- " AND sql NOT NULL",
- zSchema, zTable
- );
- output_sql_from_query(&x,
- "SELECT sql FROM \"%w\".sqlite_master "
- "WHERE sql NOT NULL"
- " AND type IN ('index','trigger','view')"
- " AND tbl_name=%Q COLLATE nocase",
- zSchema, zTable
- );
- }
+ run_schema_dump_query(&x,
+ "SELECT name, type, sql FROM sqlcipher_master "
+ "WHERE sql NOT NULL AND type=='table' AND name!='sqlcipher_sequence'"
+ );
+ run_schema_dump_query(&x,
+ "SELECT name, type, sql FROM sqlcipher_master "
+ "WHERE name=='sqlcipher_sequence'"
+ );
+ output_sql_from_query(&x,
+ "SELECT sql FROM sqlcipher_master "
+ "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
+ );
if( x.writableSchema ){
xCallback("PRAGMA writable_schema=OFF;\n", pArg);
}
xCallback(x.nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n", pArg);
sqlite3_exec(db, "COMMIT", 0, 0, 0);
- return x.rc;
+ return x.rc ?: x.nErr ? SQLITE_ERROR : SQLITE_OK;
}
/************** End of dbdump.c ************************************************/
+
+struct Out {
+ size_t reserved, empty;
+ char *p;
+};
+
+static int ssout(const char *s, void *p) {
+ struct Out *out = (struct Out *)p;
+ const size_t len = strlen(s);
+ if (len >= out->empty) {
+ const size_t expandby = out->reserved + len;
+ out->empty += expandby;
+ out->reserved += expandby;
+ char *p = (char *)realloc(out->p, out->reserved);
+ if (!p)
+ return EOF;
+ out->p = p;
+ }
+ memcpy(out->p + (out->reserved - out->empty), s, len);
+ out->empty -= len;
+ return 0;
+}
+
+__attribute__((visibility("default"))) char *dumpLegacyDb(const char *dbPath, const unsigned char *pass, size_t passSize) {
+ struct Out out;
+ out.reserved = out.empty = 1 << 12;
+ out.p = (char *)malloc(out.reserved);
+ if (!out.p)
+ return NULL;
+
+
+ sqlite3 *db;
+ int rc = sqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, 0);
+
+ if (!rc && !(rc = sqlite3_key(db, pass, passSize)) && !(rc = sqlite3_exec(db, "PRAGMA cipher_compatibility=2", 0, 0, 0)))
+ rc = sqlite3_db_dump(db, ssout, (void*)&out);
+ sqlite3_close(db);
+
+ if (rc) {
+ free(out.p);
+ return NULL;
+ }
+ out.p[out.reserved - out.empty] = '\0';
+ return out.p;
+}
PKG_CHECK_MODULES(ENCRYPTION_SCHEME_DEP
REQUIRED
openssl1.1
- libsmack)
+ libsmack
+ sqlcipher)
SET(ENCRYPTION_SCHEME_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/encryption-scheme/smack-access.cpp
${KEY_MANAGER_PATH}/service/file-system.cpp
${KEY_MANAGER_PATH}/service/for-each-file.cpp
${KEY_MANAGER_PATH}/service/key-provider.cpp
- ${KEY_MANAGER_PATH}/sqlcipher/sqlcipher.c
)
INCLUDE_DIRECTORIES(SYSTEM ${ENCRYPTION_SCHEME_DEP_INCLUDE_DIRS})
${KEY_MANAGER_PATH}/dpl/core/include
${KEY_MANAGER_PATH}/dpl/log/include
${KEY_MANAGER_PATH}/dpl/db/include
- ${KEY_MANAGER_PATH}/sqlcipher
${KEY_MANAGER_PATH}/service
${KEY_MANAGER_PATH}/crypto
)
${KEY_MANAGER_PATH}/dpl/db/include
${KEY_MANAGER_PATH}/dpl/core/include
${KEY_MANAGER_PATH}/dpl/log/include
- ${KEY_MANAGER_PATH}/sqlcipher
${KEY_MANAGER_PATH}/service
${KEY_MANAGER_PATH}/initial-values
${KEY_MANAGER_PATH}/main
resources/testme_ver1.db
resources/testme_ver2.db
resources/testme_ver3.db
+ resources/testme0_ver4.db
DESTINATION ${DB_TEST_DIR}
)
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Contact: Kyungwook Tak <k.tak@samsung.com>
*
using namespace CKM;
using namespace std::chrono;
+static void copyFile(const char *src, const char *dst)
+{
+ std::ifstream f1(src, std::fstream::binary);
+ std::ofstream f2(dst, std::fstream::trunc | std::fstream::binary);
+ f2 << f1.rdbuf();
+ f2.close();
+ f1.close();
+ BOOST_REQUIRE(f1);
+ BOOST_REQUIRE(f2);
+}
+
+void DBFixture::unlinkDb()
+{
+ for (const auto f : {m_crypto_legacy_db_fname, m_crypto_db_fname})
+ BOOST_REQUIRE_MESSAGE(!unlink(f) || errno == ENOENT, "unlink " << f);
+}
-DBFixture::DBFixture()
+DBFixture::DBFixture(DBCryptoThrows dbCryptoThrows)
{
- BOOST_CHECK(unlink(m_crypto_db_fname) == 0 || errno == ENOENT);
- init();
+ unlinkDb();
+ init(dbCryptoThrows);
}
-DBFixture::DBFixture(const char *db_fname)
+DBFixture::DBFixture(const char *legacy_db_fname, const char *db_fname, DBCryptoThrows dbCryptoThrows)
{
- BOOST_CHECK(unlink(m_crypto_db_fname) == 0 || errno == ENOENT);
+ BOOST_REQUIRE(legacy_db_fname || db_fname);
+ unlinkDb();
- // copy file
- std::ifstream f1(db_fname, std::fstream::binary);
- std::ofstream f2(m_crypto_db_fname, std::fstream::trunc | std::fstream::binary);
- f2 << f1.rdbuf();
- f2.close();
- f1.close();
+ if (legacy_db_fname)
+ copyFile(legacy_db_fname, m_crypto_legacy_db_fname);
+ if (db_fname)
+ copyFile(db_fname, m_crypto_db_fname);
- init();
+ init(dbCryptoThrows);
}
-void DBFixture::init()
+void DBFixture::init(DBCryptoThrows dbCryptoThrows)
{
high_resolution_clock::time_point srand_feed = high_resolution_clock::now();
srand(srand_feed.time_since_epoch().count());
- BOOST_REQUIRE_NO_THROW(m_db = DB::Crypto(m_crypto_db_fname, defaultPass));
+ switch (dbCryptoThrows) {
+ case DBCryptoThrows::yes:
+ BOOST_REQUIRE_THROW(m_db = DB::Crypto(m_crypto_legacy_db_fname, m_crypto_db_fname, defaultPass), Exc::DatabaseFailed);
+ break;
+ case DBCryptoThrows::no:
+ BOOST_REQUIRE_NO_THROW(m_db = DB::Crypto(m_crypto_legacy_db_fname, m_crypto_db_fname, defaultPass));
+ BOOST_REQUIRE(access(m_crypto_legacy_db_fname, F_OK) && ENOENT == errno);
+ }
}
double DBFixture::performance_get_time_elapsed_ms()
/*
- * Copyright (c) 2016-2019 Samsung Electronics Co., Ltd. All rights reserved
+ * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Contact: Kyungwook Tak <k.tak@samsung.com>
*
class DBFixture {
public:
- DBFixture();
- explicit DBFixture(const char *db_fname);
+ enum class DBCryptoThrows : bool { no, yes };
+ DBFixture(DBCryptoThrows dbCryptoThrows = DBCryptoThrows::no);
+ explicit DBFixture(const char *legacy_db_fname, const char *db_fname,
+ DBCryptoThrows dbCryptoThrows = DBCryptoThrows::no);
constexpr static const char *m_default_name = "name";
constexpr static const char *m_default_owner = "label";
CKM::DB::Crypto m_db;
private:
- void init();
+ void init(DBCryptoThrows dbCryptoThrows);
double performance_get_time_elapsed_ms();
+ static void unlinkDb();
- constexpr static const char *m_crypto_db_fname = "/tmp/testme.db";
+ constexpr static const char *m_crypto_legacy_db_fname = "/tmp/testme.db";
+ constexpr static const char *m_crypto_db_fname = "/tmp/testme0.db";
std::string m_operation;
std::chrono::high_resolution_clock::time_point m_start_time, m_end_time;
};
/*
- * Copyright (c) 2015 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2015-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void SchemeTest::RestoreDb()
{
+ m_db.reset();
restoreFile("key-7654");
restoreFile("db-key-7654");
restoreFile("db-7654");
- m_db.reset();
m_directAccessEnabled = false;
}
auto wrappedDatabaseDEK = fs.getDBDEK();
RawBuffer key = keyProvider.getPureDEK(wrappedDatabaseDEK);
- m_db.reset(new DB::Crypto(fs.getDBPath(), key));
+ m_db.reset(new DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key));
m_directAccessEnabled = true;
+
+ // Legacy db files of the form db-$uid are incompatible with upstream sqlcipher.
+ // DB::Crypto(...) converts them to db0-$uid upstream-compatible, then deletes them.
+ // This function runs DB::Crypto(...) as root so db0-$uid are root-owned.
+ // However, database files need to be accessible to USER_NAME/GROUP_NAME (ex. ReadAll()).
+ // Thus the need to fix up ownership, much like restoreFile() does.
+ BOOST_REQUIRE(!chown(RW_DATA_DIR "/db0-7654", getUid(USER_NAME), getGid(GROUP_NAME)));
}
void SchemeTest::SignVerifyItem(const Item &itemPrv, const Item &itemPub)
/*
- * Copyright (c) 2016 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Contact: Kyungwook Tak <k.tak@samsung.com>
*
}
}
-struct DBVer1Migration : public DBFixture {
- DBVer1Migration() : DBFixture(DB_TEST_DIR "/testme_ver1.db") {}
-};
-
-struct DBVer2Migration : public DBFixture {
- DBVer2Migration() : DBFixture(DB_TEST_DIR "/testme_ver2.db") {}
-};
-
-struct DBVer3Migration : public DBFixture {
- DBVer3Migration() : DBFixture(DB_TEST_DIR "/testme_ver3.db") {}
-};
+void verifyDBisValid(const char *legacyDb, const char *db)
+{
+ DBFixture DB(legacyDb, db);
+ verifyDBisValid(DB);
+}
}
POSITIVE_TEST_CASE(DBMigrationDBVer1)
{
- DBVer1Migration DBver1;
- verifyDBisValid(DBver1);
+ verifyDBisValid(DB_TEST_DIR "/testme_ver1.db", nullptr);
}
POSITIVE_TEST_CASE(DBMigrationDBVer2)
{
- DBVer2Migration DBver2;
- verifyDBisValid(DBver2);
+ verifyDBisValid(DB_TEST_DIR "/testme_ver2.db", nullptr);
}
POSITIVE_TEST_CASE(DBMigrationDBVer3)
{
- DBVer3Migration DBver3;
- verifyDBisValid(DBver3);
+ verifyDBisValid(DB_TEST_DIR "/testme_ver3.db", nullptr);
+}
+
+POSITIVE_TEST_CASE(DBMigrationDBVer3UncleanBoot)
+{
+ verifyDBisValid(DB_TEST_DIR "/testme_ver3.db", DB_TEST_DIR "/testme_ver3.db");
+}
+
+POSITIVE_TEST_CASE(DB0MigrationDBVer4)
+{
+ verifyDBisValid(nullptr, DB_TEST_DIR "/testme0_ver4.db");
+}
+
+NEGATIVE_TEST_CASE(DBMigrationInvalid)
+{
+ DBFixture(DB_TEST_DIR "/testme0_ver4.db", nullptr,
+ DBFixture::DBCryptoThrows::yes);
+}
+
+NEGATIVE_TEST_CASE(DBMigrationInvalidUncleanBoot)
+{
+ DBFixture(DB_TEST_DIR "/testme0_ver4.db", DB_TEST_DIR "/testme_ver3.db",
+ DBFixture::DBCryptoThrows::yes);
+}
+
+NEGATIVE_TEST_CASE(DBMigrationInvalid0)
+{
+ DBFixture(nullptr, DB_TEST_DIR "/testme_ver3.db",
+ DBFixture::DBCryptoThrows::yes);
}
POSITIVE_TEST_CASE(DBMigrationDBCurrent)
cynara-client-async
cynara-creds-socket
security-manager
+ sqlcipher
${CKM_DB_TOOL_EXTRA_DEP}
)
${KEY_MANAGER_PATH}/common
${KEY_MANAGER_PATH}/service
${KEY_MANAGER_PATH}/initial-values
- ${KEY_MANAGER_PATH}/sqlcipher
${KEY_MANAGER_PATH}/dpl/core/include
${KEY_MANAGER_PATH}/dpl/log/include
${KEY_MANAGER_PATH}/dpl/db/include
${KEY_MANAGER_PATH}/service/ss-migrate.cpp
${KEY_MANAGER_PATH}/service/ss-crypto.cpp
${KEY_MANAGER_PATH}/service/permission.cpp
- ${KEY_MANAGER_PATH}/sqlcipher/sqlcipher.c
)
IF(TZ_BACKEND_ENABLED)
/*
- * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
const size_t ELLIPSIS_LEN = sizeof(ELLIPSIS) / sizeof(ELLIPSIS[0]);
-const char *const SQL_TABLES = "SELECT name FROM sqlcipher_master "
- "WHERE type IN ('table','view') AND name NOT LIKE 'sqlcipher_%' "
+const char *const SQL_TABLES = "SELECT name FROM sqlite_master "
+ "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' "
"UNION ALL "
- "SELECT name FROM sqlcipher_temp_master "
+ "SELECT name FROM sqlite_temp_master "
"WHERE type IN ('table','view') "
"ORDER BY 1";
const char *const SQL_SCHEMA = "SELECT sql FROM "
- "(SELECT * FROM sqlcipher_master "
+ "(SELECT * FROM sqlite_master "
"UNION ALL "
- "SELECT * FROM sqlcipher_temp_master) "
+ "SELECT * FROM sqlite_temp_master) "
"WHERE type!='meta' AND sql!='NULL'"
"ORDER BY tbl_name, type DESC, name";
} // anonymous namespace