});
}
-int ManagerImpl::allowAccess(const std::string &/*alias*/,
- const std::string &/*accessor*/,
- AccessRight /*granted*/)
+int ManagerImpl::allowAccess(const std::string &alias,
+ const std::string &accessor,
+ AccessRight granted)
{
- return CKM_API_ERROR_UNKNOWN;
+ m_counter++;
+ int my_counter = m_counter;
+ return try_catch([&] {
+ MessageBuffer send, recv;
+ Serialization::Serialize(send, static_cast<int>(LogicCommand::ALLOW_ACCESS));
+ Serialization::Serialize(send, my_counter);
+ Serialization::Serialize(send, alias);
+ Serialization::Serialize(send, accessor);
+ Serialization::Serialize(send, static_cast<int>(granted));
+
+ int retCode = sendToServer(
+ SERVICE_SOCKET_CKM_STORAGE,
+ send.Pop(),
+ recv);
+
+ if (CKM_API_SUCCESS != retCode) {
+ return retCode;
+ }
+
+ int command;
+ int counter;
+ Deserialization::Deserialize(recv, command);
+ Deserialization::Deserialize(recv, counter);
+ Deserialization::Deserialize(recv, retCode);
+
+ if (my_counter != counter) {
+ return CKM_API_ERROR_UNKNOWN;
+ }
+
+ return retCode;
+ });
}
-int ManagerImpl::denyAccess(const std::string &/*alias*/, const std::string &/*accessor*/)
+int ManagerImpl::denyAccess(const std::string &alias, const std::string &accessor)
{
- return CKM_API_ERROR_UNKNOWN;
+ m_counter++;
+ int my_counter = m_counter;
+ return try_catch([&] {
+ MessageBuffer send, recv;
+ Serialization::Serialize(send, static_cast<int>(LogicCommand::DENY_ACCESS));
+ Serialization::Serialize(send, my_counter);
+ Serialization::Serialize(send, alias);
+ Serialization::Serialize(send, accessor);
+
+ int retCode = sendToServer(
+ SERVICE_SOCKET_CKM_STORAGE,
+ send.Pop(),
+ recv);
+
+ if (CKM_API_SUCCESS != retCode) {
+ return retCode;
+ }
+
+ int command;
+ int counter;
+ Deserialization::Deserialize(recv, command);
+ Deserialization::Deserialize(recv, counter);
+ Deserialization::Deserialize(recv, retCode);
+
+ if (my_counter != counter) {
+ return CKM_API_ERROR_UNKNOWN;
+ }
+
+ return retCode;
+ });
}
ManagerShPtr Manager::create() {
}
} // namespace CKM
-
}
}
+const char* toDBAccessRight(AccessRight access_right_type) {
+ switch(access_right_type) {
+ case AccessRight::AR_READ: return "R";
+ case AccessRight::AR_READ_REMOVE: return "RD";
+ default:
+ // TODO
+ throw 1;
+ }
+}
+
PolicySerializable::PolicySerializable()
{}
GET_CHAIN_ALIAS,
CREATE_SIGNATURE,
VERIFY_SIGNATURE,
- CREATE_KEY_PAIR_DSA
+ CREATE_KEY_PAIR_DSA,
+ ALLOW_ACCESS,
+ DENY_ACCESS,
// for backward compatibility append new on the end
};
DBDataType toDBDataType(KeyType key);
KeyType toKeyType(DBDataType dbDataType);
+const char* toDBAccessRight(AccessRight access_right_type);
class IStream;
LogError("No row for given alias and label");
retCode = CKM_API_ERROR_DB_ALIAS_UNKNOWN;
}
+ } Catch (DBCrypto::Exception::PermissionDenied) {
+ LogError("Error: not enough permissions!");
+ retCode = CKM_API_ERROR_ACCESS_DENIED;
} Catch (CKM::Exception) {
LogError("Error in deleting row!");
retCode = CKM_API_ERROR_DB_ERROR;
const Password &password,
DBRow &row)
{
-
if (0 == m_userDataMap.count(cred.uid))
return CKM_API_ERROR_DB_LOCKED;
} catch (const CryptoLogic::Exception::Base &e) {
LogError("CryptoLogic failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_SERVER_ERROR;
+ } catch (const DBCrypto::Exception::PermissionDenied &e) {
+ LogError("DBCrypto failed with message: " << e.GetMessage());
+ retCode = CKM_API_ERROR_ACCESS_DENIED;
} catch (const DBCrypto::Exception::Base &e) {
LogError("DBCrypto failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_DB_ERROR;
auto &handler = m_userDataMap[cred.uid];
Try {
if (dataType == DBDataType::CERTIFICATE || dataType == DBDataType::BINARY_DATA) {
- handler.database.getAliases(dataType, cred.smackLabel, aliasVector);
+ handler.database.getAliases(dataType, aliasVector);
} else {
- handler.database.getKeyAliases(cred.smackLabel, aliasVector);
+ handler.database.getKeyAliases(aliasVector);
}
} Catch (CKM::Exception) {
LogError("Failed to get aliases");
} catch (const CryptoLogic::Exception::Base &e) {
LogError("DBCyptorModule failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_SERVER_ERROR;
+ } catch (const DBCrypto::Exception::PermissionDenied &e) {
+ LogError("DBCrypto failed with message: " << e.GetMessage());
+ retCode = CKM_API_ERROR_ACCESS_DENIED;
} catch (const DBCrypto::Exception::Base &e) {
LogError("DBCrypto failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_DB_ERROR;
} catch (const CryptoLogic::Exception::Base &e) {
LogError("CryptoLogic failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_SERVER_ERROR;
+ } catch (const DBCrypto::Exception::PermissionDenied &e) {
+ LogError("DBCrypto failed with message: " << e.GetMessage());
+ retCode = CKM_API_ERROR_ACCESS_DENIED;
} catch (const DBCrypto::Exception::Base &e) {
LogError("DBCrypto failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_DB_ERROR;
} catch (const CryptoLogic::Exception::Base &e) {
LogError("CryptoLogic failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_SERVER_ERROR;
+ } catch (const DBCrypto::Exception::PermissionDenied &e) {
+ LogError("DBCrypto failed with message: " << e.GetMessage());
+ retCode = CKM_API_ERROR_ACCESS_DENIED;
} catch (const DBCrypto::Exception::Base &e) {
LogError("DBCrypto failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_DB_ERROR;
return response.Pop();
}
+
+RawBuffer CKMLogic::allowAccess(
+ Credentials &cred,
+ int commandId,
+ const Alias &item_alias,
+ const std::string &accessor_label,
+ const AccessRight req_rights)
+{
+ int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
+
+ if (0 < m_userDataMap.count(cred.uid))
+ {
+ Try {
+ retCode = m_userDataMap[cred.uid].database.setAccessRights(cred.smackLabel, item_alias, accessor_label, req_rights);
+ } Catch (DBCrypto::Exception::InvalidArgs) {
+ LogError("Error: invalid args!");
+ retCode = CKM_API_ERROR_INPUT_PARAM;
+ } Catch (DBCrypto::Exception::PermissionDenied) {
+ LogError("Error: not enough permissions!");
+ retCode = CKM_API_ERROR_ACCESS_DENIED;
+ } Catch (CKM::Exception) {
+ LogError("Error in set row!");
+ retCode = CKM_API_ERROR_DB_ERROR;
+ }
+ } else {
+ retCode = CKM_API_ERROR_DB_LOCKED;
+ }
+
+ MessageBuffer response;
+ Serialization::Serialize(response, static_cast<int>(LogicCommand::ALLOW_ACCESS));
+ Serialization::Serialize(response, commandId);
+ Serialization::Serialize(response, retCode);
+
+ return response.Pop();
+}
+
+RawBuffer CKMLogic::denyAccess(
+ Credentials &cred,
+ int commandId,
+ const Alias &item_alias,
+ const std::string &accessor_label)
+{
+ int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
+
+ if (0 < m_userDataMap.count(cred.uid))
+ {
+ Try {
+ retCode = m_userDataMap[cred.uid].database.clearAccessRights(cred.smackLabel, item_alias, accessor_label);
+ } Catch (DBCrypto::Exception::PermissionDenied) {
+ LogError("Error: not enough permissions!");
+ retCode = CKM_API_ERROR_ACCESS_DENIED;
+ } Catch (DBCrypto::Exception::InvalidArgs) {
+ LogError("Error: permission not found!");
+ retCode = CKM_API_ERROR_INPUT_PARAM;
+ } Catch (CKM::Exception) {
+ LogError("Error in deleting row!");
+ retCode = CKM_API_ERROR_DB_ERROR;
+ }
+ } else {
+ retCode = CKM_API_ERROR_DB_LOCKED;
+ }
+
+ MessageBuffer response;
+ Serialization::Serialize(response, static_cast<int>(LogicCommand::DENY_ACCESS));
+ Serialization::Serialize(response, commandId);
+ Serialization::Serialize(response, retCode);
+
+ return response.Pop();
+}
+
} // namespace CKM
RawBuffer setCCModeStatus(CCModeState mode_status);
+ RawBuffer allowAccess(
+ Credentials &cred,
+ int commandId,
+ const Alias &item_alias,
+ const std::string &accessor_label,
+ const AccessRight req_rights);
+
+ RawBuffer denyAccess(
+ Credentials &cred,
+ int commandId,
+ const Alias &item_alias,
+ const std::string &accessor_label);
+
private:
int saveDataHelper(
static_cast<const HashAlgorithm>(hash),
static_cast<const RSAPaddingAlgorithm>(padding));
}
+ case LogicCommand::ALLOW_ACCESS:
+ {
+ Alias item_alias;
+ std::string accessor_label;
+ int req_rights;
+ Deserialization::Deserialize(buffer, item_alias);
+ Deserialization::Deserialize(buffer, accessor_label);
+ Deserialization::Deserialize(buffer, req_rights);
+ return m_logic->allowAccess(
+ cred,
+ commandId,
+ item_alias,
+ accessor_label,
+ static_cast<AccessRight>(req_rights));
+ }
+ case LogicCommand::DENY_ACCESS:
+ {
+ Alias item_alias;
+ std::string accessor_label;
+ Deserialization::Deserialize(buffer, item_alias);
+ Deserialization::Deserialize(buffer, accessor_label);
+ return m_logic->denyAccess(
+ cred,
+ commandId,
+ item_alias,
+ accessor_label);
+ }
default:
Throw(Exception::BrokenProtocol);
}
namespace {
const char *main_table = "CKM_TABLE";
const char *key_table = "KEY_TABLE";
+ const char *permission_table = "PERMISSION_TABLE";
// CKM_TABLE (alias TEXT, label TEXT, restricted INT, exportable INT, dataType INT,
// algorithmType INT, encryptionScheme INT, iv BLOB, dataSize INT, data BLOB)
" dataSize INTEGER NOT NULL,"
" data BLOB NOT NULL,"
" tag BLOB NOT NULL,"
- " PRIMARY KEY(alias, label),"
- " UNIQUE(alias)"
+ " PRIMARY KEY(alias)"
");";
" ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
const char *select_alias_cmd =
- // 1 2 3
- "SELECT * FROM CKM_TABLE WHERE alias=? AND dataType=? AND label=?; ";
+ // 1 2
+ "SELECT * FROM CKM_TABLE WHERE alias=? AND dataType=?; ";
const char *select_check_alias_cmd =
- // 1 2
- "SELECT dataType FROM CKM_TABLE WHERE alias=? AND label=?; ";
+ // 1
+ "SELECT dataType FROM CKM_TABLE WHERE alias=?;";
const char *select_check_global_alias_cmd =
// 1
- "SELECT label FROM CKM_TABLE WHERE alias=? ;";
-
- const char *select_count_rows_cmd =
- // 1 2
- "SELECT COUNT(alias) FROM CKM_TABLE WHERE alias=? AND label=?;";
+ "SELECT label FROM CKM_TABLE WHERE alias=?;";
const char *select_key_alias_cmd =
// 1
"SELECT * FROM CKM_TABLE WHERE alias=?"
// 2 3
- " AND dataType BETWEEN ? AND ? "
- // 4
- " AND label=? ;";
+ " AND dataType BETWEEN ? AND ?;";
const char *select_key_type_cmd =
"SELECT alias FROM CKM_TABLE WHERE "
// 1
" dataType >= ? AND "
// 2
- " dataType <= ? AND "
- // 3
- " label=?;";
+ " dataType <= ?;";
const char *select_type_cmd =
- // 1 2
- "SELECT alias FROM CKM_TABLE WHERE dataType=? AND label=?;";
+ // 1
+ "SELECT alias FROM CKM_TABLE WHERE dataType=?;";
const char *delete_alias_cmd =
- // 1 2
- "DELETE FROM CKM_TABLE WHERE alias=? AND label=?;";
+ // 1
+ "DELETE FROM CKM_TABLE WHERE alias=?;";
const char *delete_data_with_key_cmd =
// 1
"SELECT key FROM KEY_TABLE WHERE label=?;";
const char *delete_key_cmd =
"DELETE FROM KEY_TABLE WHERE label=?";
+
+
+// PERMISSION_TABLE (label TEXT, label TEXT, access_flags TEXT)
+
+ const char *db_create_permission_cmd =
+ "CREATE TABLE PERMISSION_TABLE("
+ " alias TEXT NOT NULL,"
+ " label TEXT NOT NULL,"
+ " accessFlags TEXT NOT NULL,"
+ " FOREIGN KEY(alias) REFERENCES CKM_TABLE(alias) ON DELETE CASCADE,"
+ " PRIMARY KEY(label)"
+ ");";
+
+ const char *set_permission_alias_cmd =
+ "REPLACE INTO PERMISSION_TABLE(alias, label, accessFlags) VALUES (?, ?, ?);";
+
+ const char *select_permission_cmd =
+ // 1 2
+ "SELECT accessFlags FROM PERMISSION_TABLE WHERE alias=? AND label=?;";
+
+ const char *delete_permission_cmd =
+ // 1 2
+ "DELETE FROM PERMISSION_TABLE WHERE alias=? AND label=?;";
}
namespace CKM {
if(!m_connection->CheckTableExist(key_table)) {
createTable(db_create_key_cmd, key_table);
}
+ if(!m_connection->CheckTableExist(permission_table)) {
+ createTable(db_create_permission_cmd, permission_table);
+ }
transaction.commit();
}
- bool DBCrypto::checkGlobalAliasExist(const std::string& alias) {
+ std::string DBCrypto::getLabelForAlias(const std::string& alias) const {
SqlConnection::DataCommandUniquePtr checkCmd =
m_connection->PrepareDataCommand(select_check_global_alias_cmd);
checkCmd->BindString(1, alias.c_str());
if(checkCmd->Step()) {
- LogDebug("Global alias '" << alias << "' exists already for label "
- << checkCmd->GetColumnString(0));
+ return checkCmd->GetColumnString(0);
+ } else
+ return std::string();
+ }
+ bool DBCrypto::checkGlobalAliasExist(const std::string& alias) const {
+ std::string label = this->getLabelForAlias(alias);
+ if(label.empty() == false) {
+ LogDebug("Global alias '" << alias << "' exists already for label " << label);
return true;
} else
return false;
}
- bool DBCrypto::checkAliasExist(
- const std::string& alias,
- const std::string& label) {
+ bool DBCrypto::checkAliasExist(const std::string& alias) const {
SqlConnection::DataCommandUniquePtr checkCmd =
m_connection->PrepareDataCommand(select_check_alias_cmd);
checkCmd->BindString(1, alias.c_str());
- checkCmd->BindString(2, label.c_str());
if(checkCmd->Step()) {
LogDebug("Private alias '" << alias << "' exists already for type "
<< checkCmd->GetColumnInteger(0));
//Sqlite does not support partial index in our version,
//so we do it by hand
Transaction transaction(this);
- if(checkAliasExist(row.alias, row.smackLabel)) {
+ if(checkAliasExist(row.alias)) {
ThrowMsg(DBCrypto::Exception::AliasExists,
- "Alias exists for alias: " << row.alias
- << ", label: " << row.smackLabel);
+ "Alias exists for alias: " << row.alias);
}
SqlConnection::DataCommandUniquePtr insertCommand =
return row;
}
+ std::string DBCrypto::getPermissionsForAliasAndLabel(const Alias &alias, const std::string &label) const
+ {
+ Try{
+ SqlConnection::DataCommandUniquePtr selectCommand =
+ m_connection->PrepareDataCommand(select_permission_cmd);
+ selectCommand->BindString(1, alias.c_str());
+ selectCommand->BindString(2, label.c_str());
+
+ if(selectCommand->Step())
+ return selectCommand->GetColumnString(0);
+
+ return std::string();
+ } Catch (SqlConnection::Exception::InvalidColumn) {
+ LogError("Select statement invalid column error");
+ } Catch (SqlConnection::Exception::SyntaxError) {
+ LogError("Couldn't prepare select statement");
+ } Catch (SqlConnection::Exception::InternalError) {
+ LogError("Couldn't execute select statement");
+ }
+ return std::string();
+ }
+
+
+ bool DBCrypto::rowAccessControlCheck(const Alias &alias,
+ const std::string &owner_label,
+ const std::string &clnt_label,
+ DBCrypto::DBOperationType access_type) const
+ {
+ // owner of the entry have all the permissions by default
+ // check if requesting client is the entry owner - if so, exit (permission granted)
+ if(owner_label == clnt_label)
+ return true;
+
+ // perform permissions DB query
+ std::string permission_string = this->getPermissionsForAliasAndLabel(alias, clnt_label);
+
+ // check if requested operation is in the permission string
+ LogDebug("pair <" << alias << "," << clnt_label << "> permission rights: \"" << permission_string << "\"");
+ if(permission_string.find(access_type) != std::string::npos)
+ return true;
+
+ return false;
+ }
+ bool DBCrypto::rowAccessControlCheck(const DBRow & input_row,
+ const std::string &clnt_label,
+ DBCrypto::DBOperationType access_type) const
+ {
+ return this->rowAccessControlCheck(input_row.alias, input_row.smackLabel, clnt_label, access_type);
+ }
+
+
DBCrypto::DBRowOptional DBCrypto::getDBRow(
const Alias &alias,
- const std::string &label,
+ const std::string &clnt_label,
DBDataType type)
{
Try {
m_connection->PrepareDataCommand(select_alias_cmd);
selectCommand->BindString(1, alias.c_str());
selectCommand->BindInteger(2, static_cast<int>(type));
- selectCommand->BindString(3, label.c_str());
- if(selectCommand->Step()) {
+ if(selectCommand->Step())
+ {
+ // extract data
+ DBRow current_row = getRow(selectCommand);
+
+ // check access rights here
+ if( ! this->rowAccessControlCheck(current_row, clnt_label, DBCrypto::DB_OPERATION_READ) )
+ ThrowMsg(Exception::PermissionDenied, "Not enough permissions to perform requested operation");
+
+ // finalize DB operations
transaction.commit();
- return DBRowOptional(getRow(selectCommand));
+
+ // all okay, proceed
+ return DBRowOptional(current_row);
} else {
return DBRowOptional();
}
}
ThrowMsg(DBCrypto::Exception::InternalError,
"Couldn't get row for type " << static_cast<int>(type) <<
- " alias " << alias << " and label " << label);
+ " alias " << alias << " using client label " << clnt_label);
}
DBCrypto::DBRowOptional DBCrypto::getKeyDBRow(
const Alias &alias,
- const std::string &label)
+ const std::string &clnt_label)
{
Try{
Transaction transaction(this);
selectCommand->BindString(1, alias.c_str());
selectCommand->BindInteger(2, static_cast<int>(DBDataType::DB_KEY_FIRST));
selectCommand->BindInteger(3, static_cast<int>(DBDataType::DB_KEY_LAST));
- selectCommand->BindString(4, label.c_str());
- if(selectCommand->Step()) {
+ if(selectCommand->Step())
+ {
+ // extract data
+ DBRow current_row = getRow(selectCommand);
+
+ // check access rights here
+ if( ! this->rowAccessControlCheck(current_row, clnt_label, DBCrypto::DB_OPERATION_READ) )
+ ThrowMsg(Exception::PermissionDenied, "Not enough permissions to perform requested operation");
+
+ // finalize DB operations
transaction.commit();
- return DBRowOptional(getRow(selectCommand));
+
+ // all okay, proceed
+ return DBRowOptional(current_row);
} else {
return DBRowOptional();
}
}
ThrowMsg(DBCrypto::Exception::InternalError,
"Couldn't get Key for alias " << alias
- << " and label " << label);
+ << " using client label " << clnt_label);
}
void DBCrypto::getSingleType(
DBDataType type,
- const std::string& label,
- AliasVector& aliases)
+ AliasVector& aliases) const
{
Try{
SqlConnection::DataCommandUniquePtr selectCommand =
m_connection->PrepareDataCommand(select_type_cmd);
selectCommand->BindInteger(1, static_cast<int>(type));
- selectCommand->BindString(2, label.c_str());
while(selectCommand->Step()) {
Alias alias;
LogError("Couldn't execute select statement");
}
ThrowMsg(DBCrypto::Exception::InternalError,
- "Couldn't get type " << static_cast<int>(type)
- << " for label " << label);
+ "Couldn't get type " << static_cast<int>(type));
}
void DBCrypto::getAliases(
DBDataType type,
- const std::string& label,
AliasVector& aliases)
{
- getSingleType(type, label, aliases);
+ getSingleType(type, aliases);
}
- void DBCrypto::getKeyAliases(
- const std::string &label,
- AliasVector &aliases)
+ void DBCrypto::getKeyAliases(AliasVector &aliases)
{
Try{
Transaction transaction(this);
m_connection->PrepareDataCommand(select_key_type_cmd);
selectCommand->BindInteger(1, static_cast<int>(DBDataType::DB_KEY_FIRST));
selectCommand->BindInteger(2, static_cast<int>(DBDataType::DB_KEY_LAST));
- selectCommand->BindString(3, label.c_str());
while(selectCommand->Step()) {
Alias alias;
} Catch (SqlConnection::Exception::InternalError) {
LogError("Couldn't execute select statement");
}
- ThrowMsg(DBCrypto::Exception::InternalError,
- "Couldn't get key aliases for label " << label);
+ ThrowMsg(DBCrypto::Exception::InternalError, "Couldn't get key aliases");
}
- int DBCrypto::countRows(const Alias &alias, const std::string &label) {
- SqlConnection::DataCommandUniquePtr checkCmd =
- m_connection->PrepareDataCommand(select_count_rows_cmd);
- checkCmd->BindString(1, alias.c_str());
- checkCmd->BindString(2, label.c_str());
- if(checkCmd->Step()) {
- return checkCmd->GetColumnInteger(0);
- } else {
- LogDebug("Row does not exist for alias=" << alias << "and label=" << label);
- return 0;
- }
- }
- int DBCrypto::deleteDBRow(
- const Alias &alias,
- const std::string &label)
+ bool DBCrypto::deleteDBRow(const Alias &alias, const std::string &clnt_label)
{
Try {
Transaction transaction(this);
- unsigned int count;
- if((count = countRows(alias, label)) > 0) {
+
+ std::string owner_label = getLabelForAlias(alias);
+ if( ! owner_label.empty() )
+ {
+ // check access rights here
+ if( ! this->rowAccessControlCheck(alias, owner_label, clnt_label, DBCrypto::DB_OPERATION_REMOVE) )
+ ThrowMsg(Exception::PermissionDenied, "Not enough permissions to perform requested remove operation");
+
+ // if here, access right is granted - proceed with removal
+ // note: PERMISSION_TABLE entry will be deleted automatically by SQL (cascade relation between tables)
SqlConnection::DataCommandUniquePtr deleteCommand =
m_connection->PrepareDataCommand(delete_alias_cmd);
deleteCommand->BindString(1, alias.c_str());
- deleteCommand->BindString(2, label.c_str());
deleteCommand->Step();
+
transaction.commit();
+ return true;
+ }
+ else
+ {
+ LogError("Error: no such alias: " << alias);
+ return false;
}
- return count;
} Catch (SqlConnection::Exception::SyntaxError) {
LogError("Couldn't prepare delete statement");
} Catch (SqlConnection::Exception::InternalError) {
LogError("Couldn't execute delete statement");
}
ThrowMsg(DBCrypto::Exception::InternalError,
- "Couldn't delete DBRow for alias " << alias
- << " and label " << label);
+ "Couldn't delete DBRow for alias " << alias << " using client label " << clnt_label);
}
void DBCrypto::saveKey(
"Couldn't delete key for label " << label);
}
+
+ int DBCrypto::setAccessRights( const std::string& clnt_label,
+ const Alias& alias,
+ const std::string& accessor_label,
+ const AccessRight value_to_set)
+ {
+ Try {
+ Transaction transaction(this);
+
+ // check if label is present
+ std::string owner_label = getLabelForAlias(alias);
+ if( ! owner_label.empty() )
+ {
+ // owner can not add permissions to itself
+ if(owner_label.compare(accessor_label) == 0)
+ ThrowMsg(Exception::InvalidArgs, "Invalid accessor label: equal to owner label");
+
+ // check access rights here - only owner can modify permissions
+ if(owner_label != clnt_label)
+ ThrowMsg(Exception::PermissionDenied, "Not enough permissions to perform requested write operation");
+
+ // if here, access right is granted - proceed to set permissions
+ SqlConnection::DataCommandUniquePtr setPermissionCommand =
+ m_connection->PrepareDataCommand(set_permission_alias_cmd);
+ setPermissionCommand->BindString(1, alias.c_str());
+ setPermissionCommand->BindString(2, accessor_label.c_str());
+ setPermissionCommand->BindString(3, toDBAccessRight(value_to_set));
+ setPermissionCommand->Step();
+ transaction.commit();
+ return CKM_API_SUCCESS;
+ }
+ else
+ {
+ LogError("Error: no such alias: " << alias);
+ return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+ }
+ } Catch (SqlConnection::Exception::SyntaxError) {
+ LogError("Couldn't prepare set statement");
+ } Catch (SqlConnection::Exception::InternalError) {
+ LogError("Couldn't execute set statement");
+ }
+ ThrowMsg(DBCrypto::Exception::InternalError,
+ "Couldn't set permissions for alias " << alias << " using client label " << clnt_label);
+ }
+
+ int DBCrypto::clearAccessRights(const std::string& clnt_label,
+ const Alias& alias,
+ const std::string& accessor_label)
+ {
+ Try {
+ Transaction transaction(this);
+
+ std::string owner_label = getLabelForAlias(alias);
+ if( ! owner_label.empty() )
+ {
+ // check access rights here - only owner can modify permissions
+ if(owner_label != clnt_label)
+ ThrowMsg(Exception::PermissionDenied, "Not enough permissions to perform requested write operation");
+
+ // check if permission for <label, accessor_label> is defined - otherwise nothing to drop
+ if( this->getPermissionsForAliasAndLabel(alias, accessor_label).empty() )
+ ThrowMsg(Exception::InvalidArgs, "Permission not found");
+
+ // if here, access right is granted - proceed to delete permissions
+ SqlConnection::DataCommandUniquePtr deletePermissionCommand =
+ m_connection->PrepareDataCommand(delete_permission_cmd);
+ deletePermissionCommand->BindString(1, alias.c_str());
+ deletePermissionCommand->BindString(2, accessor_label.c_str());
+ deletePermissionCommand->Step();
+ transaction.commit();
+ return CKM_API_SUCCESS;
+ }
+ else
+ {
+ LogError("Error: no such alias: " << alias);
+ return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+ }
+ } Catch (SqlConnection::Exception::SyntaxError) {
+ LogError("Couldn't prepare delete statement");
+ } Catch (SqlConnection::Exception::InternalError) {
+ LogError("Couldn't execute delete statement");
+ }
+ ThrowMsg(DBCrypto::Exception::InternalError,
+ "Couldn't delete permissions for alias " << alias << " using client label " << clnt_label);
+ }
+
} // CKM
#pragma GCC diagnostic pop
DECLARE_EXCEPTION_TYPE(Base, AliasExists)
DECLARE_EXCEPTION_TYPE(Base, InternalError)
DECLARE_EXCEPTION_TYPE(Base, TransactionError)
+ DECLARE_EXCEPTION_TYPE(Base, PermissionDenied)
+ DECLARE_EXCEPTION_TYPE(Base, InvalidArgs)
};
DBCrypto() :
m_connection(NULL),
void saveDBRow(const DBRow &row);
DBRowOptional getDBRow(
const Alias &alias,
- const std::string &label,
+ const std::string &clnt_label,
DBDataType type);
DBRowOptional getKeyDBRow(
const Alias &alias,
- const std::string &label);
+ const std::string &clnt_label);
void getAliases(
DBDataType dataType,
- const std::string &label,
AliasVector &aliases);
- void getKeyAliases(
- const std::string &label,
- AliasVector &aliases);
- int deleteDBRow(
+ void getKeyAliases(AliasVector &aliases);
+ bool deleteDBRow(
const Alias& alias,
- const std::string &label);
+ const std::string &clnt_label);
+
+ // keys
void saveKey(const std::string& label, const RawBuffer &key);
RawBufferOptional getKey(
const std::string& label);
void deleteKey(const std::string& label);
+ // permissions
+ int setAccessRights(const std::string& clnt_label,
+ const Alias& alias,
+ const std::string& accessor_label,
+ const AccessRight value_to_set);
+ int clearAccessRights(const std::string& clnt_label,
+ const Alias& alias,
+ const std::string& accessor_label);
+
int beginTransaction();
int commitTransaction();
int rollbackTransaction();
void initDatabase();
DBRow getRow(const DB::SqlConnection::DataCommandUniquePtr &selectCommand);
+
+ enum DBOperationType : char {
+ DB_OPERATION_READ = 'R', ///< read DB row
+ DB_OPERATION_WRITE = 'W', ///< modify DB row
+ DB_OPERATION_REMOVE = 'D' ///< delete DB row
+ };
+
+ /**
+ * read PERMISSION_TABLE entry for pair <alias, label>
+ *
+ * @return permission string (consisting with DBOperationType chars), may be empty
+ */
+ std::string getPermissionsForAliasAndLabel(const Alias &alias, const std::string &label) const;
+
+ /**
+ * check if current requesting alias has permissions
+ * to perform operation on the given DB entry
+ *
+ * @return true if permission granted, false otherwise
+ */
+ bool rowAccessControlCheck(const DBRow & input_row,
+ const std::string &clnt_label,
+ DBOperationType access_type) const;
+ // helper
+ bool rowAccessControlCheck(const Alias &alias,
+ const std::string &owner_label,
+ const std::string &clnt_label,
+ DBOperationType access_type) const;
+
void createTable(
const char *create_cmd,
const char *table_name);
- bool checkAliasExist(
- const std::string &alias,
- const std::string &label);
- bool checkGlobalAliasExist(const std::string& alias);
- int countRows(
- const std::string &alias,
- const std::string &label);
- void getSingleType(
- DBDataType type,
- const std::string& label,
- AliasVector& aliases);
+ bool checkAliasExist(const std::string &alias) const;
+ std::string getLabelForAlias(const std::string& alias) const;
+ bool checkGlobalAliasExist(const std::string& alias) const;
+ void getSingleType(DBDataType type, AliasVector& aliases) const;
};
} // namespace CKM
#include <unistd.h>
#include <db-crypto.h>
#include <iostream>
+#include <ckm/ckm-type.h>
#include <ckm/ckm-error.h>
#include <errno.h>
using namespace CKM;
+namespace
+{
+
const char* default_alias = "alias";
const char* default_label = "label";
const int restricted_local = 1;
const int restricted_global = 0;
-DBRow createDefaultRow(DBDataType type = DBDataType::BINARY_DATA) {
+// mirrors the API-defined value
+#define AES_GCM_TAG_SIZE 16
+
+const char *row_A_alias = "row_A_alias";
+const char *row_A_label = "app_A";
+
+const char *row_B_alias = "row_B_alias";
+const char *row_B_label = "app_B";
+
+const char *row_C_alias = "row_C_alias";
+const char *row_C_label = "app_C";
+
+void initDB(DBCrypto & db)
+{
+ BOOST_CHECK(unlink(crypto_db) == 0 || errno == ENOENT);
+ BOOST_REQUIRE_NO_THROW(db = DBCrypto(crypto_db, defaultPass));
+}
+
+DBRow createDefaultRow( DBDataType type = DBDataType::BINARY_DATA,
+ const char *optional_alias = NULL,
+ const char *optional_label = NULL)
+{
DBRow row;
- row.alias = default_alias;
- row.smackLabel = default_label;
+ row.alias = optional_alias?optional_alias:default_alias;
+ row.smackLabel = optional_label?optional_label:default_label;
row.exportable = 1;
row.algorithmType = DBCMAlgType::AES_GCM_256;
row.dataType = type;
BOOST_REQUIRE_MESSAGE(!row_optional, "Select should not return row after deletion");
}
+void insertRow(DBCrypto & db, const char *alias, const char *label)
+{
+ DBRow rowPattern = createDefaultRow(DBDataType::BINARY_DATA, alias, label);
+ rowPattern.data = RawBuffer(100, 20);
+ rowPattern.dataSize = rowPattern.data.size();
+ rowPattern.tag = RawBuffer(AES_GCM_TAG_SIZE, 1);
+ BOOST_REQUIRE_NO_THROW(db.saveDBRow(rowPattern));
+}
+
+void deleteRow(DBCrypto & db, const char *alias, const char *label)
+{
+ bool exit_flag;
+ BOOST_REQUIRE_NO_THROW(exit_flag = db.deleteDBRow(alias, label));
+ BOOST_REQUIRE_MESSAGE(true == exit_flag, "remove alias failed: no rows removed");
+}
+
+void addPermission(DBCrypto & db, const char *alias, const char *owner_label, const char *accessor_label)
+{
+ int ec;
+ BOOST_REQUIRE_NO_THROW(ec = db.setAccessRights(std::string(owner_label),
+ std::string(alias),
+ std::string(accessor_label),
+ CKM::AccessRight::AR_READ_REMOVE));
+ BOOST_REQUIRE_MESSAGE(CKM_API_SUCCESS == ec, "add permission failed: " << ec);
+}
+
+void readRowExpectFail(DBCrypto & db, const char *alias, const char *accessor_label)
+{
+ DBCrypto::DBRowOptional row;
+ BOOST_REQUIRE_THROW(row = db.getDBRow(alias, accessor_label, DBDataType::BINARY_DATA), DBCrypto::Exception::PermissionDenied);
+}
+
+void readRowExpectSuccess(DBCrypto & db, const char *alias, const char *accessor_label)
+{
+ DBCrypto::DBRowOptional row;
+ BOOST_REQUIRE_NO_THROW(row = db.getDBRow(alias, accessor_label, DBDataType::BINARY_DATA));
+ BOOST_REQUIRE_MESSAGE(row, "row is empty");
+}
+}
+
BOOST_AUTO_TEST_SUITE(DBCRYPTO_TEST)
BOOST_AUTO_TEST_CASE(DBtestSimple) {
-
- BOOST_CHECK(unlink(crypto_db) == 0 || errno == ENOENT);
DBCrypto db;
- BOOST_REQUIRE_NO_THROW(db = DBCrypto(crypto_db, defaultPass));
+ initDB(db);
DBRow rowPattern = createDefaultRow();
rowPattern.data = RawBuffer(32, 1);
rowPattern.dataSize = rowPattern.data.size();
- rowPattern.tag = RawBuffer(16, 1);
+ rowPattern.tag = RawBuffer(AES_GCM_TAG_SIZE, 1);
checkDBIntegrity(rowPattern, db);
}
BOOST_AUTO_TEST_CASE(DBtestBIG) {
- BOOST_CHECK(unlink(crypto_db) == 0 || errno == ENOENT);
DBCrypto db;
- BOOST_REQUIRE_NO_THROW(db = DBCrypto(crypto_db, defaultPass));
+ initDB(db);
DBRow rowPattern = createDefaultRow();
rowPattern.data = createBigBlob(4096);
rowPattern.dataSize = rowPattern.data.size();
- rowPattern.tag = RawBuffer(16, 1);
+ rowPattern.tag = RawBuffer(AES_GCM_TAG_SIZE, 1);
checkDBIntegrity(rowPattern, db);
}
BOOST_AUTO_TEST_CASE(DBtestGlobal) {
- BOOST_CHECK(unlink(crypto_db) == 0 || errno == ENOENT);
DBCrypto db;
- BOOST_REQUIRE_NO_THROW(db = DBCrypto(crypto_db, defaultPass));
+ initDB(db);
DBRow rowPattern = createDefaultRow();
rowPattern.data = RawBuffer(1024, 2);
rowPattern.dataSize = rowPattern.data.size();
- rowPattern.tag = RawBuffer(16, 1);
+ rowPattern.tag = RawBuffer(AES_GCM_TAG_SIZE, 1);
BOOST_REQUIRE_NO_THROW(db.saveDBRow(rowPattern));
DBCrypto::Exception::AliasExists);
}
BOOST_AUTO_TEST_CASE(DBtestTransaction) {
- BOOST_CHECK(unlink(crypto_db) == 0 || errno == ENOENT);
DBCrypto db;
- BOOST_REQUIRE_NO_THROW(db = DBCrypto(crypto_db, defaultPass));
+ initDB(db);
DBRow rowPattern = createDefaultRow();
rowPattern.data = RawBuffer(100, 20);
rowPattern.dataSize = rowPattern.data.size();
- rowPattern.tag = RawBuffer(16, 1);
+ rowPattern.tag = RawBuffer(AES_GCM_TAG_SIZE, 1);
DBCrypto::Transaction transaction(&db);
BOOST_REQUIRE_NO_THROW(db.saveDBRow(rowPattern));
BOOST_CHECK_MESSAGE(!row_optional, "Row still present after rollback");
}
+
+BOOST_AUTO_TEST_CASE(DBaddDataCheckIfPermissionIsAdded)
+{
+ DBCrypto db;
+ initDB(db);
+
+ // insert initial data set
+ insertRow(db, row_A_alias, row_A_label);
+ insertRow(db, row_B_alias, row_B_label);
+ readRowExpectSuccess(db, row_A_alias, row_A_label);
+ readRowExpectSuccess(db, row_B_alias, row_B_label);
+
+ // verify that no entries present in the permission table
+ // read row A from label B and vice versa
+ readRowExpectFail(db, row_A_alias, row_B_label);
+ readRowExpectFail(db, row_B_alias, row_A_label);
+
+ // add appropriate permissions for label B
+ addPermission(db, row_A_alias, row_A_label, row_B_label);
+
+ // B should have access to A, while A should not to B
+ // read row A from label B and vice versa
+ readRowExpectSuccess(db, row_A_alias, row_B_label);
+ readRowExpectFail(db, row_B_alias, row_A_label);
+
+ // add appropriate permissions for label A
+ addPermission(db, row_B_alias, row_B_label, row_A_label);
+
+ // B should have access to A, same as A have access to B
+ // read row A from label B and vice versa
+ readRowExpectSuccess(db, row_A_alias, row_B_label);
+ readRowExpectSuccess(db, row_B_alias, row_A_label);
+}
+
+
+BOOST_AUTO_TEST_CASE(DBremoveDataCheckIfPermissionIsRemoved)
+{
+ DBCrypto db;
+ initDB(db);
+
+ // insert initial data set
+ insertRow(db, row_A_alias, row_A_label);
+ insertRow(db, row_B_alias, row_B_label);
+ insertRow(db, row_C_alias, row_C_label);
+ addPermission(db, row_A_alias, row_A_label, row_B_label);
+ addPermission(db, row_B_alias, row_B_label, row_A_label);
+ // to test multiple permissions removal
+ // put intentionally after row_B_alias permission entry
+ addPermission(db, row_A_alias, row_A_label, row_C_label);
+
+ // B should have access to A, same as A have access to B
+ // read row A from label B and vice versa
+ readRowExpectSuccess(db, row_A_alias, row_B_label);
+ readRowExpectSuccess(db, row_A_alias, row_C_label);
+ readRowExpectSuccess(db, row_B_alias, row_A_label);
+ readRowExpectFail(db, row_B_alias, row_C_label);
+
+ // remove data A - expect permissions for B and C to be removed as well
+ deleteRow(db, row_A_alias, row_A_label);
+ // insert it again - expect permissions for label B and C not to be there anymore
+ insertRow(db, row_A_alias, row_A_label);
+
+ // read row A from label B and vice versa
+ readRowExpectFail(db, row_A_alias, row_B_label);
+ readRowExpectFail(db, row_A_alias, row_C_label);
+ readRowExpectSuccess(db, row_B_alias, row_A_label);
+
+ // remove data B - expect permission to be removed as well
+ deleteRow(db, row_B_alias, row_B_label);
+ // insert it again - expect permissions for label A not to be there anymore
+ insertRow(db, row_B_alias, row_B_label);
+
+ // read row A from label B and vice versa
+ readRowExpectFail(db, row_A_alias, row_B_label);
+ readRowExpectFail(db, row_A_alias, row_C_label);
+ readRowExpectFail(db, row_B_alias, row_A_label);
+
+ // sanity check: data exists
+ readRowExpectSuccess(db, row_A_alias, row_A_label);
+ readRowExpectSuccess(db, row_B_alias, row_B_label);
+}
+
+
BOOST_AUTO_TEST_SUITE_END()