Newer
Older
mbed-os / features / storage / TESTS / kvstore / securestore_whitebox / main.cpp
/*
* Copyright (c) 2018 ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/

#include "SecureStore.h"
#include "TDBStore.h"
#ifdef MBED_CONF_RTOS_PRESENT
#include "Thread.h"
#endif
#include "mbed_error.h"
#include "Timer.h"
#include "HeapBlockDevice.h"
#include "FlashSimBlockDevice.h"
#include "SlicingBlockDevice.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>

#if !SECURESTORE_ENABLED || !KVSTORE_ENABLED
#error [NOT_SUPPORTED] KVStore & SecureStore need to be enabled for this test
#endif

using namespace mbed;

const size_t ul_bd_size  = 8 * 4096;
const size_t rbp_bd_size = 4 * 4096;

static const int heap_alloc_threshold_size = 4096;

#undef TEST_SPIF
#undef TEST_FSSTORE_UL
#undef NO_RBP_MODE

#ifdef TEST_SPIF
#include "SPIFBlockDevice.h"
SPIFBlockDevice flash_bd(MBED_CONF_SPIF_DRIVER_SPI_MOSI, MBED_CONF_SPIF_DRIVER_SPI_MISO,
                         MBED_CONF_SPIF_DRIVER_SPI_CLK, MBED_CONF_SPIF_DRIVER_SPI_CS);
SlicingBlockDevice ul_bd(&flash_bd, 0, ul_bd_size);
SlicingBlockDevice rbp_bd(&flash_bd, ul_bd_size, ul_bd_size + rbp_bd_size);
#else
HeapBlockDevice bd(ul_bd_size + rbp_bd_size, 1, 1, 4096);
FlashSimBlockDevice flash_bd(&bd);
SlicingBlockDevice ul_bd(&flash_bd, 0, ul_bd_size);
SlicingBlockDevice rbp_bd(&flash_bd, ul_bd_size, ul_bd_size + rbp_bd_size);
#endif

#ifdef TEST_FSSTORE_UL
#include "LittleFileSystem.h"
#include "FileSystemStore.h"
#endif

using namespace utest::v1;

static const char *const key1      = "key1";
static const char *const key1_val1 = "val1";
static const char *const key2      = "name_of_key2";
static const char *const key2_val1 = "val3";
static const char *const key2_val2 = "val2 of key 2";
static const char *const key2_val3 = "Val1 value of key 2            ";
static const char *const key3      = "This_is_the_name_of_key3";
static const char *const key3_val1 = "Data value of key 3 is the following";
static const char *const key3_val2 = "Unfollow";
static const char *const key4      = "This_is_the_name_of_key4";
static const char *const key4_val1 = "Is this the value of key 4?";
static const char *const key4_val2 = "What the hell is the value of key 4, god damn it!";
static const char *const key5      = "This_is_the_real_name_of_Key5";
static const char *const key5_val1 = "Key 5 value that should definitely be written";
static const char *const key5_val2 = "Key 5 value that should definitely not be written";
static const char *const key6      = "Key6_name";
static const char *const key6_val1 = "Value 1 of key6";
static const char *const key6_val2 = "Value 2 of key6. That's it.";
static const char *const key7      = "Key7";
static const char *const key7_val1 = "7 is a lucky number";

static void white_box_test()
{
    uint8_t get_buf[256];
    size_t actual_data_size;
    int result;
    mbed::Timer timer;
    int elapsed;
    KVStore::info_t info;

    uint8_t *dummy = new (std::nothrow) uint8_t[heap_alloc_threshold_size];
    TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough heap to run test");

    // We need to skip the test if we don't have enough memory for the heap block device.
    // However, this device allocates the erase units on the fly, so "erase" it via the flash
    // simulator. A failure here means we haven't got enough memory.
    flash_bd.init();
    result = flash_bd.erase(0, flash_bd.size());
    TEST_SKIP_UNLESS_MESSAGE(!result, "Not enough heap to run test");
    flash_bd.deinit();

    delete[] dummy;

#ifdef TEST_FSSTORE_UL
    LittleFileSystem *fs = new LittleFileSystem("fs", &ul_bd);

    result = fs->mount(&ul_bd);

    if (result) {
        result = fs->reformat(&ul_bd);
        TEST_ASSERT_EQUAL(0, result);
    }

    FileSystemStore *ul_kv = new FileSystemStore(fs);
#else
    TDBStore *ul_kv = new TDBStore(&ul_bd);
#endif

#ifdef NO_RBP_MODE
    TDBStore *rbp_kv = 0;
#else
    TDBStore *rbp_kv = new TDBStore(&rbp_bd);
#endif

    SecureStore *sec_kv = new SecureStore(ul_kv, rbp_kv);

    for (int i = 0; i < 2; i++) {
        timer.reset();
        result = sec_kv->init();
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        elapsed = timer.read_ms();
        printf("Elapsed time for init %d ms\n", elapsed);

        timer.reset();
        result = sec_kv->reset();
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        elapsed = timer.read_ms();
        printf("Elapsed time for reset is %d ms\n", elapsed);

        result = sec_kv->set(key1, key1_val1, strlen(key1_val1), KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_INTEGRITY_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->set(key2, key2_val1, strlen(key2_val1), KVStore::REQUIRE_INTEGRITY_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->set(key2, key2_val2, strlen(key2_val2), KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_INTEGRITY_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->get(key2, get_buf, sizeof(get_buf), &actual_data_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(strlen(key2_val2), actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key2_val2, get_buf, strlen(key2_val2));

        timer.reset();
        result = sec_kv->set(key2, key2_val3, strlen(key2_val3), KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG);
        elapsed = timer.read_ms();
        printf("Elapsed time for set is %d ms\n", elapsed);

        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->set(key3, key3_val1, strlen(key3_val1),
                             KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->set(key3, key3_val2, strlen(key3_val2),
                             KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_CONFIDENTIALITY_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_INVALID_ARGUMENT, result);

        result = sec_kv->get(key3, get_buf, sizeof(get_buf), &actual_data_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(strlen(key3_val1), actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key3_val1, get_buf, strlen(key3_val1));

        for (int j = 0; j < 2; j++) {
            result = sec_kv->set(key4, key4_val1, strlen(key4_val1),
                                 KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG);
            TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

            result = sec_kv->set(key4, key4_val2, strlen(key4_val2),
                                 KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG);
            TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        }

        result = sec_kv->get_info(key3, &info);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG, info.flags);
        TEST_ASSERT_EQUAL(strlen(key3_val1), info.size);

        result = ul_kv->get_info(key3, &info);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(0, info.flags);

#ifndef NO_RBP_MODE
        result = rbp_kv->get_info(key3, &info);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
#endif

        result = sec_kv->remove(key3);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->remove(key3);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_ITEM_NOT_FOUND, result);

        result = ul_kv->get_info(key3, &info);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_ITEM_NOT_FOUND, result);

#ifndef NO_RBP_MODE
        result = rbp_kv->get_info(key3, &info);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_ITEM_NOT_FOUND, result);
#endif

        result = sec_kv->get_info(key5, &info);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_ITEM_NOT_FOUND, result);

        result = sec_kv->set(key5, key5_val1, strlen(key5_val1),
                             KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG | KVStore::WRITE_ONCE_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

#ifndef NO_RBP_MODE
        result = rbp_kv->get_info(key5, &info);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(KVStore::WRITE_ONCE_FLAG, info.flags);
#endif

        result = sec_kv->set(key5, key5_val2, strlen(key5_val2),
                             KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG | KVStore::WRITE_ONCE_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_WRITE_PROTECTED, result);

        result = sec_kv->remove(key5);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_WRITE_PROTECTED, result);

        result = sec_kv->get(key5, get_buf, sizeof(get_buf), &actual_data_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(strlen(key5_val1), actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key5_val1, get_buf, strlen(key5_val1));

        result = sec_kv->get(key1, get_buf, sizeof(get_buf), &actual_data_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(strlen(key1_val1), actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key1_val1, get_buf, strlen(key1_val1));

        timer.reset();
        result = sec_kv->get(key2, get_buf, sizeof(get_buf), &actual_data_size);
        elapsed = timer.read_ms();
        printf("Elapsed time for get is %d ms\n", elapsed);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(strlen(key2_val3), actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key2_val3, get_buf, strlen(key2_val3));

        result = sec_kv->get(key4, get_buf, sizeof(get_buf), &actual_data_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(strlen(key4_val2), actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key4_val2, get_buf, strlen(key4_val2));

        result = sec_kv->get(key4, get_buf, 7, &actual_data_size, 30);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(7, actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key4_val2 + 30, get_buf, 7);

        result = sec_kv->get(key5, get_buf, sizeof(get_buf), &actual_data_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(strlen(key5_val1), actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key5_val1, get_buf, strlen(key5_val1));

        KVStore::iterator_t it;
        char *char_get_buf = reinterpret_cast <char *>(get_buf);

        result = sec_kv->iterator_open(&it, "This");
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->iterator_next(it, char_get_buf, sizeof(get_buf));
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        bool got_key4 = !strcmp(key4, char_get_buf);
        bool got_key5 = !strcmp(key5, char_get_buf);
        TEST_ASSERT_EQUAL(true, got_key4 || got_key5);

        result = sec_kv->iterator_next(it, char_get_buf, sizeof(get_buf));
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        if (got_key4) {
            TEST_ASSERT_EQUAL_STRING(key5, char_get_buf);
        } else {
            TEST_ASSERT_EQUAL_STRING(key4, char_get_buf);
        }

        result = sec_kv->iterator_next(it, (char *)get_buf, sizeof(get_buf));
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_ITEM_NOT_FOUND, result);

        result = sec_kv->iterator_close(it);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->deinit();
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        timer.reset();
        result = sec_kv->init();
        elapsed = timer.read_ms();
        printf("Elapsed time for init is %d ms\n", elapsed);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->get(key4, get_buf, sizeof(get_buf), &actual_data_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(strlen(key4_val2), actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(key4_val2, get_buf, strlen(key4_val2));

        result = sec_kv->set(key6, key6_val1, strlen(key6_val1),
                             KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

#ifndef NO_RBP_MODE
        // Simulate a rollback attack
        char attack_buf[sizeof(get_buf)];
        size_t attack_size;
        result = ul_kv->get(key6, attack_buf, sizeof(attack_buf), &attack_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->set(key6, key6_val2, strlen(key6_val2),
                             KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = ul_kv->set(key6, attack_buf, attack_size, 0);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->get_info(key6, 0);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_RBP_AUTHENTICATION_FAILED, result);

        // Make sure encrypted data is truly encrypted
        result = rbp_kv->get_info(key6, &info);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        int cmac_size = info.size;
        uint8_t *cmac = new uint8_t[cmac_size];

        result = sec_kv->set(key7, key7_val1, strlen(key7_val1), KVStore::REQUIRE_INTEGRITY_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = ul_kv->get(key7, attack_buf, sizeof(attack_buf), &attack_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        int data_offset = attack_size - cmac_size - strlen(key7_val1);
        TEST_ASSERT_EQUAL(0, strncmp(key7_val1, attack_buf + data_offset, strlen(key7_val1)));

        result = sec_kv->set(key7, key7_val1, strlen(key7_val1), KVStore::REQUIRE_INTEGRITY_FLAG | KVStore::REQUIRE_CONFIDENTIALITY_FLAG);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = ul_kv->get(key7, attack_buf, sizeof(attack_buf), &attack_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_NOT_EQUAL(0, strncmp(key7_val1, attack_buf + data_offset, strlen(key7_val1)));

        // Simulate a wrong CMAC
        result = ul_kv->get(key7, attack_buf, attack_size - cmac_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        result = ul_kv->get(key7, cmac, cmac_size, &actual_data_size, attack_size - cmac_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        cmac[0]++;

        KVStore::set_handle_t handle;
        result = ul_kv->set_start(&handle, key7, attack_size, 0);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = ul_kv->set_add_data(handle, attack_buf, attack_size - cmac_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        result = ul_kv->set_add_data(handle, cmac, cmac_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        result = ul_kv->set_finalize(handle);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = ul_kv->get(key7, attack_buf, sizeof(attack_buf), &attack_size);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

        result = sec_kv->get_info(key7, 0);
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_AUTHENTICATION_FAILED, result);

        delete[] cmac;
#endif

        result = sec_kv->deinit();
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
    }

    delete sec_kv;
    delete ul_kv;
    delete rbp_kv;

#ifdef TEST_FSSTORE_UL
    delete fs;
#endif
}

#if 0
static void multi_set_test()
{
    char *key;
    uint8_t *get_buf, *set_buf;
    size_t key_size = 32;
    size_t data_size = 512;
    size_t num_keys = 16;
    size_t set_iters = 3;
    size_t actual_data_size;
    int result;
    mbed::Timer timer;
    int elapsed;
    size_t i;
    uint8_t key_ind;

    timer.start();
#if !defined(TEST_SPIF) && !defined(TEST_SD)
    HeapBlockDevice heap_bd(4096 * 64, 1,  1, 4096);
    FlashSimBlockDevice flash_bd(&heap_bd);
#endif

    // TODO: Fix
    KVStore *kvs = new TDBStore(&flash_bd);

    timer.reset();
    result = kvs->init();
    elapsed = timer.read_ms();
    printf("Elapsed time for initial init is %d ms\n", elapsed);
    TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

    key = new char[key_size + 1];
    get_buf = new uint8_t[data_size];
    set_buf = new uint8_t[data_size];

    srand(1);
    for (i = 0; i < key_size; i++) {
        // printable characters only
        key[i] = rand() % 223 + 32;
    }
    key[key_size] = '\0';

    for (i = 0; i < data_size; i++) {
        set_buf[i] = rand() % 256;
    }

    int max_set_time = 0, total_set_time = 0;
    int max_get_time = 0, total_get_time = 0;

    timer.reset();
    result = kvs->reset();
    elapsed = timer.read_ms();
    TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

    for (i = 0; i < set_iters; i++) {
        for (key_ind = 0; key_ind < num_keys; key_ind++) {
            key[0] = '0' + key_ind;
            set_buf[0] = key_ind * (i + 1);
            timer.reset();
            result = kvs->set(key, set_buf, data_size, 0);
            elapsed = timer.read_ms();
            TEST_ASSERT_EQUAL(0, result);
            if (elapsed > max_set_time) {
                max_set_time = elapsed;
            }
            total_set_time += elapsed;
        }
    }

    for (key_ind = 0; key_ind < num_keys; key_ind++) {
        key[0] = '0' + key_ind;
        set_buf[0] = key_ind * set_iters;
        timer.reset();
        result = kvs->get(key, get_buf, data_size, &actual_data_size);
        elapsed = timer.read_ms();
        TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
        TEST_ASSERT_EQUAL(data_size, actual_data_size);
        TEST_ASSERT_EQUAL_STRING_LEN(set_buf, get_buf, data_size);
        if (elapsed > max_get_time) {
            max_get_time = elapsed;
        }
        total_get_time += elapsed;
    }

    printf("set time: Total (%d * %d times) - %d ms, Average - %d ms, Max - %d ms\n",
           set_iters, num_keys, total_set_time,
           total_set_time / (set_iters * num_keys), max_set_time);
    printf("get time: Total (%d times)      - %d ms, Average - %d ms, Max - %d ms\n",
           num_keys, total_get_time,
           total_get_time / num_keys, max_get_time);

    result = kvs->deinit();
    TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

    timer.reset();
    result = kvs->init();
    elapsed = timer.read_ms();
    printf("Elapsed time for init is %d ms\n", elapsed);
    TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

    result = kvs->deinit();
    TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);

    delete[] key;
    delete[] get_buf;
    delete[] set_buf;

    delete kvs;
}
#endif



utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
{
    greentea_case_failure_abort_handler(source, reason);
    return STATUS_CONTINUE;
}

Case cases[] = {
    Case("SecureStore: White box test",     white_box_test,    greentea_failure_handler),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(120, "default_auto");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    return !Harness::run(specification);
}