summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>2015-09-24 11:21:03 +0200
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>2015-10-27 07:25:44 +0100
commitd31fd54fd0a5edc0b1049ab4394a9dedbf13b72e (patch)
tree79c141f69ea6edc7763b5bb871cb48392fd5d0ae
parentcbb7712357af6b734a876b6d66e72ab1efb294ee (diff)
downloadkey-manager-d31fd54fd0a5edc0b1049ab4394a9dedbf13b72e.tar.gz
key-manager-d31fd54fd0a5edc0b1049ab4394a9dedbf13b72e.tar.bz2
key-manager-d31fd54fd0a5edc0b1049ab4394a9dedbf13b72e.zip
Add encryption scheme tests
[Problem] We need tests that will verify correctness of old and new encryption scheme support. [Solution] Tests added. [Verification] Run ckm-tests-internal -t ENCRYPTION_SCHEME_TEST Change-Id: I9f4e24a9e06684d401540646d5560287e35b828d
-rw-r--r--tests/CMakeLists.txt3
-rw-r--r--tests/encryption-scheme/CMakeLists.txt32
-rw-r--r--tests/encryption-scheme/scheme-test.cpp406
-rw-r--r--tests/encryption-scheme/scheme-test.h65
-rw-r--r--tests/test_encryption-scheme.cpp152
5 files changed, 644 insertions, 14 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 62fea85d..8cadd638 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -29,6 +29,7 @@ INCLUDE_DIRECTORIES(
${KEY_MANAGER_PATH}/client-async/
${KEY_MANAGER_SRC_PATH}/include
${KEY_MANAGER_TEST_MERGED_SRC}/
+ ${KEY_MANAGER_TEST_MERGED_SRC}/encryption-scheme/
)
SET(TEST_MERGED_SOURCES
@@ -44,6 +45,7 @@ SET(TEST_MERGED_SOURCES
${KEY_MANAGER_TEST_MERGED_SRC}/test_comm-manager.cpp
${KEY_MANAGER_TEST_MERGED_SRC}/test_serialization.cpp
${KEY_MANAGER_TEST_MERGED_SRC}/test_xml-parser.cpp
+ ${KEY_MANAGER_TEST_MERGED_SRC}/test_encryption-scheme.cpp
${KEY_MANAGER_PATH}/service/db-crypto.cpp
${KEY_MANAGER_PATH}/service/key-provider.cpp
${KEY_MANAGER_PATH}/initial-values/parser.cpp
@@ -62,6 +64,7 @@ TARGET_LINK_LIBRARIES(${TARGET_TEST_MERGED}
${TARGET_KEY_MANAGER_COMMON}
${CMAKE_THREAD_LIBS_INIT}
${KEY_MANAGER_DEP_LIBRARIES}
+ ${TARGET_ENCRYPTION_SCHEME_COMMON}
boost_unit_test_framework
-ldl
)
diff --git a/tests/encryption-scheme/CMakeLists.txt b/tests/encryption-scheme/CMakeLists.txt
index 85038590..10cea932 100644
--- a/tests/encryption-scheme/CMakeLists.txt
+++ b/tests/encryption-scheme/CMakeLists.txt
@@ -21,16 +21,39 @@ INCLUDE(FindPkgConfig)
# common encryption scheme library
PKG_CHECK_MODULES(ENCRYPTION_SCHEME_DEP
- libsmack
- REQUIRED)
+ REQUIRED
+ openssl
+ libcrypto
+ libsmack)
+
+FIND_PACKAGE(Threads REQUIRED)
SET(ENCRYPTION_SCHEME_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/smack-access.cpp
${CMAKE_CURRENT_SOURCE_DIR}/scheme-test.cpp
+
+ ${KEY_MANAGER_PATH}/service/file-lock.cpp
+ ${KEY_MANAGER_PATH}/service/key-provider.cpp
+ ${KEY_MANAGER_PATH}/service/db-crypto.cpp
+ ${KEY_MANAGER_PATH}/service/file-system.cpp
+ ${KEY_MANAGER_PATH}/dpl/core/src/assert.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
)
INCLUDE_DIRECTORIES(SYSTEM ${ENCRYPTION_SCHEME_DEP_INCLUDE_DIRS})
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} )
+INCLUDE_DIRECTORIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+
+ ${KEY_MANAGER_PATH}/common
+ ${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
+)
ADD_LIBRARY(${TARGET_ENCRYPTION_SCHEME_COMMON} STATIC ${ENCRYPTION_SCHEME_SOURCES})
@@ -38,6 +61,9 @@ TARGET_LINK_LIBRARIES(${TARGET_ENCRYPTION_SCHEME_COMMON}
${ENCRYPTION_SCHEME_DEP_LIBRARIES}
${TARGET_KEY_MANAGER_CLIENT}
${TARGET_KEY_MANAGER_CONTROL_CLIENT}
+ ${CMAKE_THREAD_LIBS_INIT}
+ boost_unit_test_framework
+ -ldl
)
INSTALL(TARGETS ${TARGET_ENCRYPTION_SCHEME_COMMON} DESTINATION ${LIB_INSTALL_DIR})
diff --git a/tests/encryption-scheme/scheme-test.cpp b/tests/encryption-scheme/scheme-test.cpp
index 5422bd2f..102bb690 100644
--- a/tests/encryption-scheme/scheme-test.cpp
+++ b/tests/encryption-scheme/scheme-test.cpp
@@ -22,13 +22,25 @@
#include <sys/smack.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sendfile.h>
+#include <fcntl.h>
#include <unistd.h>
+#include <string.h>
#include <fstream>
#include <stdexcept>
+#include <boost/test/unit_test.hpp>
+
#include <smack-access.h>
+#include <db-crypto.h>
+#include <file-system.h>
+#include <key-provider.h>
+#include <db-row.h>
+#include <crypto-init.h>
+
using namespace CKM;
using namespace std;
@@ -37,9 +49,13 @@ const uid_t UID = 7654;
const gid_t GID = 7654;
const char* const DBPASS = "db-pass";
const char* const LABEL = "my-label";
+const Label DB_LABEL = "/" + string(LABEL);
+const int ENC_SCHEME_OFFSET = 24;
const string TEST_DATA_STR = "test-data";
RawBuffer TEST_DATA(TEST_DATA_STR.begin(), TEST_DATA_STR.end());
const Password TEST_PASS = "custom user password";
+const size_t IV_LEN = 16;
+const size_t CHAIN_LEN = 3;
enum {
NO_PASS = 0,
@@ -59,9 +75,9 @@ Policy policy[2][2] = {
struct Group {
enum {
- KEY_PAIR,
- CERT_CHAIN,
- SINGLE_ITEM
+ SINGLE_ITEM,
+ KEY_PAIR_RSA,
+ CERT_CHAIN
} type;
Items items;
};
@@ -76,24 +92,24 @@ Group GROUPS[] = {
}},
// RSA keys
- { Group::KEY_PAIR, {
+ { Group::KEY_PAIR_RSA, {
Item("key-rsa-alias-prv1", DataType::KEY_RSA_PRIVATE, policy[NO_PASS][NO_EXP]),
Item("key-rsa-alias-pub1", DataType::KEY_RSA_PUBLIC, policy[NO_PASS][NO_EXP])
}},
- { Group::KEY_PAIR, {
+ { Group::KEY_PAIR_RSA, {
Item("key-rsa-alias-prv2", DataType::KEY_RSA_PRIVATE, policy[NO_PASS][EXP]),
Item("key-rsa-alias-pub2", DataType::KEY_RSA_PUBLIC, policy[NO_PASS][EXP]),
}},
- { Group::KEY_PAIR, {
+ { Group::KEY_PAIR_RSA, {
Item("key-rsa-alias-prv3", DataType::KEY_RSA_PRIVATE, policy[PASS][NO_EXP]),
Item("key-rsa-alias-pub3", DataType::KEY_RSA_PUBLIC, policy[PASS][NO_EXP]),
}},
- { Group::KEY_PAIR, {
+ { Group::KEY_PAIR_RSA, {
Item("key-rsa-alias-prv4", DataType::KEY_RSA_PRIVATE, policy[PASS][EXP]),
Item("key-rsa-alias-pub4", DataType::KEY_RSA_PUBLIC, policy[PASS][EXP]),
}},
// different policies
- { Group::KEY_PAIR, {
+ { Group::KEY_PAIR_RSA, {
Item("key-rsa-alias-prv5", DataType::KEY_RSA_PRIVATE, policy[PASS][NO_EXP]),
Item("key-rsa-alias-pub5", DataType::KEY_RSA_PUBLIC, policy[NO_PASS][EXP]),
}},
@@ -223,12 +239,71 @@ std::string TEST_LEAF =
"Zj/T1JkYXKkEwZU6nAR2jdZp3EP9xj3o15V/tyFcXHx6l8NTxn4cJb+Xe4VquQJz\n"
"6ON7PVe0ABN/AlwVQiFE\n"
"-----END CERTIFICATE-----\n";
+
+
+
+struct FdCloser {
+ void operator()(int* fd) {
+ if(fd)
+ close(*fd);
+ }
+};
+
+typedef std::unique_ptr<int, FdCloser> FdPtr;
+
+void restoreFile(const string& filename) {
+ string sourcePath = "/usr/share/ckm-db-test/" + filename;
+ string targetPath = "/opt/data/ckm/" + filename;
+
+ int ret;
+
+ int sourceFd = TEMP_FAILURE_RETRY(open(sourcePath.c_str(), O_RDONLY));
+ BOOST_REQUIRE_MESSAGE(sourceFd > 0, "Opening " << sourcePath << " failed.");
+
+ FdPtr sourceFdPtr(&sourceFd);
+
+ int targetFd = TEMP_FAILURE_RETRY(creat(targetPath.c_str(), 666));
+ BOOST_REQUIRE_MESSAGE(targetFd > 0, "Creating " << targetPath << " failed.");
+
+ FdPtr targetFdPtr(&targetFd);
+
+ struct stat sourceStat;
+ ret = fstat(sourceFd, &sourceStat);
+ BOOST_REQUIRE_MESSAGE(ret != -1, "fstat() failed: " << ret);
+
+ ret = sendfile(targetFd, sourceFd, 0, sourceStat.st_size);
+ BOOST_REQUIRE_MESSAGE(ret != -1, "sendfile failed: " << ret);
+
+ ret = fsync(targetFd);
+ BOOST_REQUIRE_MESSAGE(ret != -1, "fsync failed: " << ret);
+}
+
+void generateRandom(size_t random_bytes, unsigned char *output)
+{
+ if(random_bytes<=0 || !output)
+ throw runtime_error("Invalid param");
+
+ std::ifstream is("/dev/urandom", std::ifstream::binary);
+ if(!is)
+ throw runtime_error("Failed to read /dev/urandom");
+ is.read(reinterpret_cast<char*>(output), random_bytes);
+ if(static_cast<std::streamsize>(random_bytes) != is.gcount())
+ throw runtime_error("Not enough bytes read from /dev/urandom");
+}
+
+RawBuffer createRandomBuffer(size_t random_bytes)
+{
+ RawBuffer buffer(random_bytes);
+ generateRandom(buffer.size(), buffer.data());
+ return buffer;
+}
} // namespace anonymous
-SchemeTest::SchemeTest() : m_userChanged(false) {
+SchemeTest::SchemeTest() : m_userChanged(false), m_directAccessEnabled(false) {
m_control = Control::create();
m_mgr = Manager::create();
+ initOpenSsl();
SmackAccess sa;
sa.add("System", LABEL, "rwx");
@@ -243,6 +318,14 @@ SchemeTest::~SchemeTest() {
} catch (...) {}
}
+void SchemeTest::RemoveUserData() {
+ if(CKM_API_SUCCESS != m_control->lockUserKey(UID))
+ throw runtime_error("lockUserKey failed");
+
+ if(CKM_API_SUCCESS != m_control->removeUserData(UID))
+ throw runtime_error("removeUserData failed");
+}
+
void SchemeTest::SwitchToUser() {
if (m_userChanged)
return;
@@ -309,7 +392,7 @@ void SchemeTest::FillDb() {
for(const auto& g:GROUPS) {
switch (g.type) {
- case Group::KEY_PAIR:
+ case Group::KEY_PAIR_RSA:
if(g.items.size() != 2)
throw runtime_error("Wrong number of keys");
if( g.items[0].type != DataType::KEY_RSA_PRIVATE ||
@@ -366,3 +449,306 @@ void SchemeTest::FillDb() {
}
}
}
+
+void SchemeTest::ReadAll(bool useWrongPass) {
+ SwitchToUser();
+
+ for(const auto& g:GROUPS) {
+ for(const auto& i:g.items) {
+ int ret;
+ Password pass = i.policy.password;
+ if(useWrongPass) {
+ if(pass.empty())
+ pass = TEST_PASS;
+ else
+ pass = Password();
+ }
+
+ switch (i.type) {
+ case DataType::BINARY_DATA:
+ {
+ RawBuffer receivedData;
+ ret = m_mgr->getData(i.alias, pass, receivedData);
+ BOOST_REQUIRE_MESSAGE(useWrongPass || receivedData == TEST_DATA,
+ "Received data is different for " << i.alias);
+ break;
+ }
+
+ case DataType::KEY_AES:
+ case DataType::KEY_RSA_PRIVATE:
+ case DataType::KEY_RSA_PUBLIC:
+ {
+ KeyShPtr receivedKey;
+ ret = m_mgr->getKey(i.alias, pass, receivedKey);
+ break;
+ }
+
+ case DataType::CERTIFICATE:
+ {
+ CertificateShPtr receivedCert;
+ ret = m_mgr->getCertificate(i.alias, pass, receivedCert);
+ break;
+ }
+
+ case DataType::CHAIN_CERT_0: // pkcs
+ {
+ PKCS12ShPtr pkcs;
+ ret = m_mgr->getPKCS12(i.alias, pass, pass, pkcs);
+ break;
+ }
+
+ default:
+ BOOST_FAIL("Unsupported data type " << i.type);
+ }
+
+ if(i.policy.extractable) {
+ if(useWrongPass)
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_ERROR_AUTHENTICATION_FAILED,
+ "Reading item " << i.alias << " should fail with " <<
+ CKM_API_ERROR_AUTHENTICATION_FAILED << " got: " << ret);
+ else
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "Reading item " << i.alias <<
+ " failed with " << ret);
+ }
+ else
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_ERROR_NOT_EXPORTABLE, "Item " << i.alias <<
+ " should not be exportable");
+ }
+ }
+}
+
+void SchemeTest::SignVerify() {
+ SwitchToUser();
+
+ for(const auto& g:GROUPS) {
+ if(g.type == Group::KEY_PAIR_RSA) {
+ BOOST_REQUIRE_MESSAGE(g.items.size() == 2, "Wrong number of keys");
+ BOOST_REQUIRE_MESSAGE(g.items[0].type == DataType::KEY_RSA_PRIVATE &&
+ g.items[1].type == DataType::KEY_RSA_PUBLIC, "Wrong key");
+
+ SignVerifyItem(g.items[0], g.items[1]);
+ } else {
+ for(const auto& i:g.items) {
+ switch (i.type) {
+ case DataType::CHAIN_CERT_0:
+ SignVerifyItem(i, i);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+void SchemeTest::EncryptDecrypt() {
+ SwitchToUser();
+
+ for(const auto& g:GROUPS) {
+ if(g.type == Group::KEY_PAIR_RSA) {
+ BOOST_REQUIRE_MESSAGE(g.items.size() == 2, "Wrong number of keys");
+ BOOST_REQUIRE_MESSAGE(g.items[0].type == DataType::KEY_RSA_PRIVATE &&
+ g.items[1].type == DataType::KEY_RSA_PUBLIC, "Wrong key");
+
+ EncryptDecryptItem(g.items[0], g.items[1]);
+ } else {
+ for(const auto& i:g.items) {
+ switch (i.type) {
+ case DataType::KEY_AES:
+ EncryptDecryptItem(i);
+ break;
+
+ case DataType::CHAIN_CERT_0:
+ EncryptDecryptItem(i, i);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+void SchemeTest::CreateChain() {
+ SwitchToUser();
+
+ for(const auto& g:GROUPS) {
+ if(g.type == Group::CERT_CHAIN) {
+ BOOST_REQUIRE_MESSAGE(g.items.size() == CHAIN_SIZE, "Not enough certificates");
+ for(const auto& c:g.items)
+ BOOST_REQUIRE_MESSAGE(c.type == DataType::CERTIFICATE, "Wrong item type");
+ Items trusted(CHAIN_SIZE-1);
+ std::copy(g.items.begin(), g.items.begin() + CHAIN_SIZE-1, trusted.begin());
+
+ // last one is ee (leaf)
+ CreateChainItem(g.items.back(), trusted);
+ } else {
+ for(const auto& i:g.items) {
+ if(i.type == DataType::CHAIN_CERT_0) // PKCS
+ CreateChainItem(i, { i });
+ }
+ }
+ }
+}
+
+void SchemeTest::RemoveAll() {
+ SwitchToUser();
+
+ for(const auto& g:GROUPS) {
+ for(const auto& i:g.items) {
+ int ret = m_mgr->removeAlias(i.alias);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
+ "removeAlias() failed with " << ret << " for " << i.alias);
+ }
+ }
+}
+size_t SchemeTest::CountObjects() {
+ EnableDirectDbAccess();
+
+ size_t ret = 0;
+ for(const auto& g:GROUPS) {
+ for(const auto& i:g.items) {
+ DB::RowVector rows;
+ // it is assumed that aliases are different
+ m_db->getRows(i.alias, DB_LABEL, DataType::DB_FIRST, DataType::DB_LAST, rows);
+ ret += rows.size();
+ }
+ }
+ return ret;
+}
+
+void SchemeTest::RestoreDb() {
+ restoreFile("key-7654");
+ restoreFile("db-key-7654");
+ restoreFile("db-7654");
+ m_db.reset();
+ m_directAccessEnabled = false;
+}
+
+void SchemeTest::CheckSchemeVersion(const ItemFilter& filter, int version) {
+ EnableDirectDbAccess();
+
+ for(const auto& g:GROUPS) {
+ for(const auto& i:g.items) {
+ if(!filter.Matches(i))
+ continue;
+
+ DB::RowVector rows;
+ m_db->getRows(i.alias, DB_LABEL, filter.typeFrom, filter.typeTo, rows);
+ BOOST_REQUIRE_MESSAGE(rows.size() > 0, "No rows found for " << i.alias);
+ for(const auto& r : rows) {
+ BOOST_REQUIRE_MESSAGE(
+ (r.encryptionScheme >> ENC_SCHEME_OFFSET) == version,
+ "Wrong encryption scheme for " << i.alias << ". Expected " << version <<
+ " got: " << (r.encryptionScheme >> ENC_SCHEME_OFFSET));
+ }
+ }
+ }
+}
+
+void SchemeTest::EnableDirectDbAccess() {
+ SwitchToRoot();
+
+ if(m_directAccessEnabled)
+ return;
+
+ // direct access to db
+ FileSystem fs(UID);
+ auto wrappedDKEK = fs.getDKEK();
+ auto keyProvider = KeyProvider(wrappedDKEK, DBPASS);
+
+ auto wrappedDatabaseDEK = fs.getDBDEK();
+ RawBuffer key = keyProvider.getPureDEK(wrappedDatabaseDEK);
+
+ m_db.reset(new DB::Crypto(fs.getDBPath(), key));
+ m_directAccessEnabled = true;
+}
+
+void SchemeTest::SignVerifyItem(const Item& itemPrv, const Item& itemPub) {
+ int ret;
+ KeyShPtr receivedKey;
+ RawBuffer signature;
+ // create/verify signature
+ ret = m_mgr->createSignature(itemPrv.alias,
+ itemPrv.policy.password,
+ TEST_DATA,
+ HashAlgorithm::SHA512,
+ RSAPaddingAlgorithm::X931,
+ signature);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "createSignature() failed with " << ret <<
+ " for " << itemPrv.alias);
+ ret = m_mgr->verifySignature(itemPub.alias,
+ itemPub.policy.password,
+ TEST_DATA,
+ signature,
+ HashAlgorithm::SHA512,
+ RSAPaddingAlgorithm::X931);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "verifySignature() failed with " << ret <<
+ " for " << itemPub.alias);
+
+}
+
+void SchemeTest::EncryptDecryptItem(const Item& item) {
+ CryptoAlgorithm algo;
+ RawBuffer iv = createRandomBuffer(IV_LEN);
+ RawBuffer encrypted, decrypted;
+ int ret;
+
+ algo.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GCM);
+ algo.setParam(ParamName::ED_IV, iv);
+
+ ret = m_mgr->encrypt(algo, item.alias, item.policy.password, TEST_DATA, encrypted);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "encrypt() failed iwth " << ret << " for " <<
+ item.alias);
+
+ ret = m_mgr->decrypt(algo, item.alias, item.policy.password, encrypted, decrypted);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "decrypt() failed iwth " << ret << " for " <<
+ item.alias);
+
+ BOOST_REQUIRE_MESSAGE(decrypted == TEST_DATA, "Decrypted data not equal to original");
+}
+
+void SchemeTest::EncryptDecryptItem(const Item& itemPrv, const Item& itemPub) {
+ CryptoAlgorithm algo;
+ RawBuffer encrypted, decrypted;
+ int ret;
+
+ algo.setParam(ParamName::ALGO_TYPE, AlgoType::RSA_OAEP);
+
+ ret = m_mgr->encrypt(algo, itemPub.alias, itemPub.policy.password, TEST_DATA, encrypted);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "encrypt() failed iwth " << ret << " for " <<
+ itemPub.alias);
+
+ ret = m_mgr->decrypt(algo, itemPrv.alias, itemPrv.policy.password, encrypted, decrypted);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "decrypt() failed iwth " << ret << " for " <<
+ itemPrv.alias);
+
+ BOOST_REQUIRE_MESSAGE(decrypted == TEST_DATA, "Decrypted data not equal to original");
+}
+
+void SchemeTest::CreateChainItem(const Item& leaf, const Items& certs) {
+ CertificateShPtrVector chain;
+ AliasVector trusted;
+
+ if(!leaf.policy.extractable || !leaf.policy.password.empty())
+ return;
+
+ for(const auto& i : certs) {
+ if(!i.policy.extractable || !i.policy.password.empty())
+ return;
+ trusted.push_back(i.alias);
+ }
+
+ CertificateShPtr leafCrt;
+ int ret = m_mgr->getCertificate(leaf.alias, leaf.policy.password, leafCrt);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
+ "getCertificate failed with " << ret << " for " <<
+ leaf.alias);
+
+ ret = m_mgr->getCertificateChain(leafCrt, AliasVector(), trusted, false, chain);
+ BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
+ "getCertificateChain() failed with " << ret);
+ BOOST_REQUIRE_MESSAGE(chain.size() == CHAIN_LEN, "Wrong chain length: " << chain.size());
+}
diff --git a/tests/encryption-scheme/scheme-test.h b/tests/encryption-scheme/scheme-test.h
index 69edd24b..6d020b71 100644
--- a/tests/encryption-scheme/scheme-test.h
+++ b/tests/encryption-scheme/scheme-test.h
@@ -21,15 +21,23 @@
#pragma once
+#include <memory>
#include <string>
+#include <vector>
#include <ckm/ckm-control.h>
#include <ckm/ckm-manager.h>
#include <data-type.h>
+namespace CKM {
+namespace DB {
+class Crypto;
+} // DB
+} // CKM
+
struct Item {
- Item() : type(CKM::DataType::DB_FIRST){}
+ Item() {}
Item(const CKM::Alias& alias,
const CKM::DataType::Type type,
const CKM::Policy& policy)
@@ -44,19 +52,74 @@ struct Item {
typedef std::vector<Item> Items;
+struct ItemFilter {
+ ItemFilter() :
+ typeFrom(CKM::DataType::DB_FIRST),
+ typeTo(CKM::DataType::DB_LAST),
+ exportableOnly(false),
+ noPassword(false)
+ {}
+
+ explicit ItemFilter(CKM::DataType::Type type) :
+ typeFrom(type),
+ typeTo(type),
+ exportableOnly(false),
+ noPassword(false)
+ {}
+
+ ItemFilter(CKM::DataType::Type typeFrom, CKM::DataType::Type typeTo) :
+ typeFrom(typeFrom),
+ typeTo(typeTo),
+ exportableOnly(false),
+ noPassword(false)
+ {}
+
+ bool Matches(const Item& item) const {
+ if(item.type < typeFrom || item.type > typeTo)
+ return false;
+ if(exportableOnly && !item.policy.extractable)
+ return false;
+ if(noPassword && !item.policy.password.empty())
+ return false;
+ return true;
+ }
+
+ CKM::DataType::Type typeFrom;
+ CKM::DataType::Type typeTo;
+ bool exportableOnly;
+ bool noPassword;
+};
+
class SchemeTest {
public:
SchemeTest();
~SchemeTest();
+ void RemoveUserData();
void FillDb();
+ void ReadAll(bool useWrongPass = false);
+ void SignVerify();
+ void EncryptDecrypt();
+ void CreateChain();
+ void RemoveAll();
+ size_t CountObjects();
+ void RestoreDb();
+ void CheckSchemeVersion(const ItemFilter& filter, int version);
private:
void SwitchToUser();
void SwitchToRoot();
+ void EnableDirectDbAccess();
+ void SignVerifyItem(const Item& itemPrv, const Item& itemPub);
+ void EncryptDecryptItem(const Item& item);
+ void EncryptDecryptItem(const Item& itemPrv, const Item& itemPub);
+ void CreateChainItem(const Item& leaf, const Items& certs);
CKM::ControlShPtr m_control;
CKM::ManagerShPtr m_mgr;
std::string m_origLabel;
bool m_userChanged;
+
+ std::unique_ptr<CKM::DB::Crypto> m_db;
+ bool m_directAccessEnabled;
};
diff --git a/tests/test_encryption-scheme.cpp b/tests/test_encryption-scheme.cpp
new file mode 100644
index 00000000..9e4579a3
--- /dev/null
+++ b/tests/test_encryption-scheme.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015 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
+ */
+/*
+ * @file test_encryption-scheme.cpp
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/results_reporter.hpp>
+
+#include <scheme-test.h>
+
+using namespace CKM;
+
+namespace {
+// this is done to limit the amount of code included in binary
+const int OLD_ENC_SCHEME = 0;
+const int NEW_ENC_SCHEME = 1;
+} // namespace anonymous
+
+
+BOOST_AUTO_TEST_SUITE(ENCRYPTION_SCHEME_TEST)
+
+// Test database should have the old scheme
+BOOST_AUTO_TEST_CASE(T010_Check_old_scheme) {
+ SchemeTest test;
+ test.RestoreDb();
+
+ ItemFilter filter;
+ test.CheckSchemeVersion(filter, OLD_ENC_SCHEME);
+}
+
+// Newly written data should use the new scheme
+BOOST_AUTO_TEST_CASE(T020_Check_new_scheme) {
+ SchemeTest test;
+ test.RemoveUserData();
+ test.FillDb();
+
+ ItemFilter filter;
+ test.CheckSchemeVersion(filter, NEW_ENC_SCHEME);
+}
+
+BOOST_AUTO_TEST_CASE(T030_Remove_old_scheme) {
+ SchemeTest test;
+ test.RestoreDb();
+ test.RemoveAll();
+
+ size_t aliases = test.CountObjects();
+ BOOST_REQUIRE_MESSAGE(aliases == 0, "All aliases should be removed");
+}
+
+BOOST_AUTO_TEST_CASE(T040_Remove_new_scheme) {
+ SchemeTest test;
+ test.RemoveUserData();
+ test.FillDb();
+ test.RemoveAll();
+
+ size_t aliases = test.CountObjects();
+ BOOST_REQUIRE_MESSAGE(aliases == 0, "All aliases should be removed");
+}
+
+// Reading old db should reencrypt objects with new scheme
+BOOST_AUTO_TEST_CASE(T100_Read) {
+ SchemeTest test;
+ test.RestoreDb();
+ test.ReadAll();
+
+ ItemFilter filter;
+ filter.exportableOnly = true;
+ test.CheckSchemeVersion(filter, NEW_ENC_SCHEME);
+}
+
+BOOST_AUTO_TEST_CASE(T110_Count_objects_after_read) {
+ SchemeTest test;
+ test.RestoreDb();
+ size_t orig = test.CountObjects();
+ BOOST_REQUIRE_MESSAGE(orig > 0, "No objects in db");
+
+ test.ReadAll();
+
+ size_t current = test.CountObjects();
+ BOOST_REQUIRE_MESSAGE(current == orig,
+ "Original number of objects: " << orig << " Current: " << current);
+}
+
+// Reading old db with incorrect passwords should leave the scheme unchanged
+BOOST_AUTO_TEST_CASE(T120_Read_wrong_pass) {
+ SchemeTest test;
+ test.RestoreDb();
+ test.ReadAll(true);
+
+ ItemFilter filter;
+ test.CheckSchemeVersion(filter, OLD_ENC_SCHEME);
+}
+
+// Signing/verification should reencrypt objects with new scheme
+BOOST_AUTO_TEST_CASE(T200_SignVerify) {
+ SchemeTest test;
+ test.RestoreDb();
+ test.SignVerify();
+
+ ItemFilter filter(DataType::KEY_RSA_PUBLIC, DataType::KEY_RSA_PRIVATE);
+ test.CheckSchemeVersion(filter, NEW_ENC_SCHEME);
+}
+
+// Encryption/decryption should reencrypt objects with new scheme
+BOOST_AUTO_TEST_CASE(T210_EncryptDecrypt) {
+ SchemeTest test;
+ test.RestoreDb();
+ test.EncryptDecrypt();
+
+ ItemFilter filter1(DataType::KEY_RSA_PUBLIC, DataType::KEY_RSA_PRIVATE);
+ test.CheckSchemeVersion(filter1, NEW_ENC_SCHEME);
+
+ ItemFilter filter2(DataType::KEY_AES);
+ test.CheckSchemeVersion(filter2, NEW_ENC_SCHEME);
+}
+
+// Chain creation should reencrypt objects with new scheme
+BOOST_AUTO_TEST_CASE(T220_CreateChain) {
+ SchemeTest test;
+ test.RestoreDb();
+ test.CreateChain();
+
+ // non exportable certificates and certificates protected with passwords can't be used for chain
+ // creation
+ ItemFilter filter1(DataType::CERTIFICATE);
+ filter1.exportableOnly = true;
+ filter1.noPassword = true;
+ test.CheckSchemeVersion(filter1, NEW_ENC_SCHEME);
+
+ ItemFilter filter2(DataType::CHAIN_CERT_0, DataType::CHAIN_CERT_15);
+ filter2.exportableOnly = true;
+ filter2.noPassword = true;
+ test.CheckSchemeVersion(filter2, NEW_ENC_SCHEME);
+}
+
+BOOST_AUTO_TEST_SUITE_END()