Add more KeyProvider tests 05/282805/1 accepted/tizen/unified/20221102.020616
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 11 Oct 2022 15:42:57 +0000 (17:42 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 11 Oct 2022 15:42:57 +0000 (17:42 +0200)
This includes tests for newly added key format and migration.

Change-Id: I852fa672ad39599dc89ac3a7b334c7e914c71bde

src/manager/service/key-provider.h
unit-tests/test_key-provider.cpp

index 5acfef5..1d6a6c2 100644 (file)
@@ -133,8 +133,9 @@ public:
 
        void migrateDomainKEK(const RawBuffer &wrappedDomainKEKbuffer, const Password &password);
 
-private:
+protected:
        std::shared_ptr<DomainKEKAndInfo> m_domainKEK;
+private:
        bool m_isInitialized;
 };
 
index 2d6530b..a44824b 100644 (file)
@@ -27,6 +27,8 @@
 #include <test_common.h>
 #include <iostream>
 
+#include "crypto-backend.h"
+
 using namespace CKM;
 
 namespace {
@@ -37,6 +39,17 @@ const Password NEW_PASSWORD = "NEW12345TIZEN12345NEW";
 const std::string USERNAME = "SOFTWARE_CENTER_SYSTEM_SW_LAB";
 const std::string CLIENT_ID = "SAMPLE_CLIENT_ID_1";
 
+constexpr uint32_t KEYCOMPONENT_VERSION = 2; // keep it in sync with key-provider.cpp
+
+template<typename T>
+RawBuffer toRawBuffer(const T &data)
+{
+       RawBuffer output;
+       const unsigned char *ptr = reinterpret_cast<const unsigned char *>(&data);
+       output.assign(ptr, ptr + sizeof(T));
+       return output;
+}
+
 RawBuffer makeDefaultWrappedDomainKEK()
 {
        RawBuffer wdkek;
@@ -55,10 +68,102 @@ KeyProvider makeDefaultKeyProvider()
        return kp;
 }
 
+RawBuffer makeDefaultWrappedDomainKEK(CryptoBackend backend)
+{
+       struct TestKeyProvider : public KeyProvider {
+               using KeyProvider::KeyProvider;
+
+               void setBackend(CryptoBackend backend) {
+                       BOOST_REQUIRE(m_domainKEK);
+                       m_domainKEK->info.backend = static_cast<uint32_t>(backend);
+               }
+       };
+
+       auto wrappedDKEKbuffer = makeDefaultWrappedDomainKEK();
+       TestKeyProvider kp(wrappedDKEKbuffer, PASSWORD);
+       kp.setBackend(backend);
+       return kp.getWrappedDomainKEK(PASSWORD);
+}
+
+void checkVersionAndBackend(const RawBuffer& wrappedDomainKEKbuffer)
+{
+       DomainKEKAndInfo wdkek(wrappedDomainKEKbuffer);
+       BOOST_REQUIRE(wdkek.info.version == KEYCOMPONENT_VERSION);
+#if SE_BACKEND_ENABLED
+       BOOST_REQUIRE(wdkek.info.backend == static_cast<uint32_t>(CryptoBackend::SecureElement));
+#else
+       BOOST_REQUIRE(wdkek.info.backend == static_cast<uint32_t>(CryptoBackend::OpenSSL));
+#endif
+}
+
+RawBuffer convertToOldFormat(const RawBuffer& wrappedDKEKbuffer)
+{
+       DomainKEKAndInfo wrappedDKEK(wrappedDKEKbuffer);
+       DEKAndInfo wrappedOldDKEK;
+
+       // hacky conversion to old key format
+       wrappedOldDKEK.setKeyInfo(static_cast<KeyInfo>(wrappedDKEK.info));
+       memcpy(wrappedOldDKEK.key, wrappedDKEK.key, wrappedDKEK.info.keyLength);
+
+       return toRawBuffer(wrappedOldDKEK);
+}
+
 } // anonymous namespace
 
 BOOST_AUTO_TEST_SUITE(KEY_PROVIDER_TEST)
 
+NEGATIVE_TEST_CASE(KeyAndInfo_ctor_wrong_size)
+{
+       RawBuffer buffer(sizeof(DomainKEKAndInfo) + 1, 0);
+       BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer)), Exc::InternalError);
+       buffer.pop_back();
+       buffer.pop_back();
+       BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer)), Exc::InternalError);
+
+       buffer.resize(sizeof(DEKAndInfo) + 1, 0);
+       BOOST_REQUIRE_THROW((DEKAndInfo(buffer)), Exc::InternalError);
+       buffer.pop_back();
+       buffer.pop_back();
+       BOOST_REQUIRE_THROW((DEKAndInfo(buffer)), Exc::InternalError);
+}
+
+NEGATIVE_TEST_CASE(KeyAndInfo_ctor_wrong_key_length)
+{
+       DomainKEKAndInfo dkek;
+       dkek.info.keyLength = MAX_KEY_SIZE+1;
+       auto buffer = toRawBuffer(dkek);
+
+       BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer)), Exc::InternalError);
+
+       DEKAndInfo dek;
+       dek.info.keyLength = MAX_KEY_SIZE+1;
+       auto buffer2 = toRawBuffer(dek);
+
+       BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer2)), Exc::InternalError);
+}
+
+NEGATIVE_TEST_CASE(KeyAndInfo_ctor_wrong_client)
+{
+       DomainKEKAndInfo dkek;
+       memset(&dkek.info.client, 'a', MAX_CLIENT_ID_SIZE);
+       auto buffer = toRawBuffer(dkek);
+
+       BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer)), Exc::InternalError);
+
+       DEKAndInfo dek;
+       memset(&dek.info.client, 'a', MAX_CLIENT_ID_SIZE);
+       auto buffer2 = toRawBuffer(dek);
+
+       BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer2)), Exc::InternalError);
+}
+
+POSITIVE_TEST_CASE(KeyAndInfo_ctor)
+{
+       BOOST_REQUIRE_NO_THROW(DomainKEKAndInfo(RawBuffer(sizeof(DomainKEKAndInfo), 0)));
+
+       BOOST_REQUIRE_NO_THROW(DEKAndInfo(RawBuffer(sizeof(DEKAndInfo), 0)));
+}
+
 NEGATIVE_TEST_CASE(KeyProvider_wrong_size)
 {
        RawBuffer wdkek = makeDefaultWrappedDomainKEK();
@@ -96,6 +201,8 @@ POSITIVE_TEST_CASE(KeygetPureDomainKEK)
 
        BOOST_REQUIRE_NO_THROW(dkek = kp.getPureDomainKEK());
        BOOST_REQUIRE(dkek.size() <= MAX_KEY_SIZE);
+
+       checkVersionAndBackend(kp.getWrappedDomainKEK("whatever"));
 }
 
 NEGATIVE_TEST_CASE(KeygetPureDomainKEK_uninitialized)
@@ -179,6 +286,13 @@ NEGATIVE_TEST_CASE(KeyGetPureDEK_garbage)
        BOOST_REQUIRE_THROW(kp.getPureDEK(wdek), Exc::InternalError);
 }
 
+POSITIVE_TEST_CASE(WrappedDomainKEK)
+{
+       RawBuffer wdkekBuffer = makeDefaultWrappedDomainKEK();
+
+       checkVersionAndBackend(wdkekBuffer);
+}
+
 POSITIVE_TEST_CASE(KeyReencrypt)
 {
        RawBuffer wdkek = makeDefaultWrappedDomainKEK();
@@ -234,9 +348,7 @@ NEGATIVE_TEST_CASE(dek_and_info)
 
        DEKAndInfo dai2;
        dai2.info.keyLength = MAX_KEY_SIZE + 1;
-
-       const unsigned char *ptr = reinterpret_cast<const unsigned char *>(&dai2);
-       RawBuffer buffer(ptr, ptr + sizeof(dai2));
+       auto buffer = toRawBuffer(dai2);
        BOOST_REQUIRE_THROW(new DEKAndInfo((buffer)), Exc::InternalError);
 
        // missing NULL termination in dai3.info.client
@@ -276,4 +388,81 @@ NEGATIVE_TEST_CASE(moves)
        BOOST_REQUIRE_THROW(kp.getPureDomainKEK(), Exc::InternalError);
 }
 
+NEGATIVE_TEST_CASE(migration)
+{
+       // migration may only happen in case of openssl backend
+       auto wrappedDKEKbuffer = makeDefaultWrappedDomainKEK(CryptoBackend::OpenSSL);
+
+       KeyProvider kp(RawBuffer(), "whatever");
+       BOOST_REQUIRE(!kp.isInitialized());
+
+       // migration possible only from old shorter format
+       BOOST_REQUIRE_THROW(kp.migrateDomainKEK(wrappedDKEKbuffer, PASSWORD), Exc::InternalError);
+       BOOST_REQUIRE(!kp.isInitialized());
+
+       auto wrappedOldDKEKbuffer = convertToOldFormat(wrappedDKEKbuffer);
+
+       KeyProvider kp2(wrappedOldDKEKbuffer, PASSWORD);
+       BOOST_REQUIRE(!kp2.isInitialized());
+       BOOST_REQUIRE_THROW(kp2.migrateDomainKEK(wrappedOldDKEKbuffer, INCORRECT_PASSWORD),
+                           Exc::AuthenticationFailed);
+       BOOST_REQUIRE(!kp2.isInitialized());
+}
+
+POSITIVE_TEST_CASE(migration)
+{
+       // migration may only happen in case of openssl backend
+       auto wrappedDKEKbuffer = makeDefaultWrappedDomainKEK(CryptoBackend::OpenSSL);
+       KeyProvider kp(wrappedDKEKbuffer, PASSWORD);
+
+       auto wrappedOldDKEKbuffer = convertToOldFormat(wrappedDKEKbuffer);
+
+       KeyProvider kp2;
+       BOOST_REQUIRE_NO_THROW(kp2 = KeyProvider(wrappedOldDKEKbuffer, PASSWORD));
+       BOOST_REQUIRE(!kp2.isInitialized());
+       BOOST_REQUIRE_NO_THROW(kp2.migrateDomainKEK(wrappedOldDKEKbuffer, PASSWORD));
+       BOOST_REQUIRE(kp2.isInitialized());
+
+       BOOST_REQUIRE(kp.getPureDomainKEK() == kp2.getPureDomainKEK());
+
+       checkVersionAndBackend(kp2.getWrappedDomainKEK("whatever"));
+}
+
+NEGATIVE_TEST_CASE(version)
+{
+       auto wrappedDKEKbuffer = makeDefaultWrappedDomainKEK();
+       DomainKEKAndInfo wrappedDKEK(wrappedDKEKbuffer);
+       wrappedDKEK.info.version = 0;
+
+       auto wrappedWrongVersionBuffer = toRawBuffer(wrappedDKEK);
+       BOOST_REQUIRE_THROW(KeyProvider(wrappedWrongVersionBuffer, PASSWORD), Exc::InternalError);
+}
+
+NEGATIVE_TEST_CASE(backend)
+{
+       auto throwForBackend = [](CryptoBackend backend){
+               BOOST_REQUIRE_THROW(KeyProvider(makeDefaultWrappedDomainKEK(backend), PASSWORD),
+                                   Exc::InternalError);
+       };
+
+       throwForBackend(CryptoBackend::None);
+       throwForBackend(CryptoBackend::TrustZone);
+       throwForBackend(static_cast<CryptoBackend>(999));
+
+#ifndef SE_BACKEND_ENABLED
+       throwForBackend(CryptoBackend::SecureElement);
+#endif
+}
+
+#ifdef SE_BACKEND_ENABLED
+POSITIVE_TEST_CASE(backend)
+{
+       KeyProvider kp;
+       BOOST_REQUIRE_NO_THROW(
+               kp = KeyProvider(makeDefaultWrappedDomainKEK(CryptoBackend::OpenSSL), PASSWORD));
+       DomainKEKAndInfo wdkek(kp.getWrappedDomainKEK("whatever"));
+       BOOST_REQUIRE(wdkek.info.backend == static_cast<uint32_t>(CryptoBackend::OpenSSL));
+}
+#endif
+
 BOOST_AUTO_TEST_SUITE_END()