Revision:
0:25fa8795676b
diff -r 000000000000 -r 25fa8795676b simple-mbed-cloud-client/mbed-cloud-client/source/CloudClientStorage.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simple-mbed-cloud-client/mbed-cloud-client/source/CloudClientStorage.c	Sun Apr 18 15:20:23 2021 +0000
@@ -0,0 +1,357 @@
+// ----------------------------------------------------------------------------
+// Copyright 2016-2017 ARM Ltd.
+//
+// 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 <string.h>
+#include <assert.h>
+#include "key_config_manager.h"
+#include "CloudClientStorage.h"
+#include "mbed-trace/mbed_trace.h"
+#include "mbed-client-libservice/common_functions.h"
+
+#define TRACE_GROUP "mClt"
+
+ccs_status_e uninitialize_storage(void)
+{
+    tr_debug("CloudClientStorage::uninitialize_storage");
+
+    kcm_status_e status = kcm_finalize();
+    if(status != KCM_STATUS_SUCCESS) {
+        tr_error("CloudClientStorage::uninitialize_storage - error %d", status);
+        return CCS_STATUS_ERROR;
+    }
+    return CCS_STATUS_SUCCESS;
+}
+
+ccs_status_e initialize_storage(void)
+{
+    tr_debug("CloudClientStorage::initialize_storage");
+    kcm_status_e status = kcm_init();
+    if(status != KCM_STATUS_SUCCESS) {
+        tr_error("CloudClientStorage::::initialize_storage - error %d", status);
+        return CCS_STATUS_ERROR;
+    }
+    return CCS_STATUS_SUCCESS;
+}
+
+ccs_status_e ccs_get_string_item(const char* key,
+                                 uint8_t *buffer,
+                                 const size_t buffer_size,
+                                 ccs_item_type_e item_type)
+{
+    size_t len = 0;
+    ccs_status_e status = ccs_get_item(key, buffer, buffer_size - 1, &len, item_type);
+
+    if (status == CCS_STATUS_SUCCESS) {
+        // Null terminate after buffer value
+        buffer[len] = 0;
+    }
+
+    return status;
+}
+
+ccs_status_e ccs_check_item(const char* key, ccs_item_type_e item_type)
+{
+    if (key == NULL) {
+        return CCS_STATUS_ERROR;
+    }
+
+    size_t real_size = 0;
+    kcm_status_e kcm_status = kcm_item_get_data_size((const uint8_t*)key, strlen(key), (kcm_item_type_e)item_type, &real_size);
+    if (kcm_status == KCM_STATUS_ITEM_NOT_FOUND) {
+        return CCS_STATUS_KEY_DOESNT_EXIST;
+    }
+    return CCS_STATUS_SUCCESS;
+}
+
+ccs_status_e ccs_delete_item(const char* key, ccs_item_type_e item_type)
+{
+    if (key == NULL) {
+        tr_error("CloudClientStorage::ccs_delete_item error, invalid parameters");
+        return CCS_STATUS_ERROR;
+    }
+
+    ccs_status_e status = ccs_check_item(key, item_type);
+    if (status == CCS_STATUS_KEY_DOESNT_EXIST) {
+        // No need to call delete as item does not exist.
+        tr_debug("CloudClientStorage::ccs_delete_item [%s], type [%d] does not exist. Not deleting anything.", key, item_type);
+        return CCS_STATUS_SUCCESS;
+    } else if (status == CCS_STATUS_ERROR) {
+        return CCS_STATUS_ERROR;
+    }
+
+    // Delete parameter from storage
+    tr_debug("CloudClientStorage::ccs_delete_item [%s], type [%d] ", key, item_type);
+    kcm_status_e kcm_status = kcm_item_delete((const uint8_t*)key,
+                                  strlen(key),
+                                  (kcm_item_type_e)item_type);
+
+    if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_debug("CloudClientStorage::ccs_delete_item [%s] kcm error %d", key, kcm_status);
+        return CCS_STATUS_ERROR;
+    }
+
+    return CCS_STATUS_SUCCESS;
+}
+
+ccs_status_e ccs_item_size(const char* key, size_t* size_out, ccs_item_type_e item_type)
+{
+    if (key == NULL) {
+        tr_error("CloudClientStorage::ccs_item_size error, invalid parameters");
+        return CCS_STATUS_ERROR;
+    }
+
+    tr_debug("CloudClientStorage::ccs_item_size [%s], item [%d]", key, item_type);
+
+    // Get kcm item size
+    kcm_status_e kcm_status = kcm_item_get_data_size((const uint8_t*)key,
+                                         strlen(key),
+                                         (kcm_item_type_e)item_type,
+                                         size_out);
+
+    if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_debug("CloudClientStorage::ccs_item_size [%s] kcm error %d", key, kcm_status);
+        return CCS_STATUS_ERROR;
+    }
+
+    return CCS_STATUS_SUCCESS;
+}
+
+ccs_status_e ccs_get_item(const char* key,
+                          uint8_t *buffer,
+                          const size_t buffer_size,
+                          size_t *value_length,
+                          ccs_item_type_e item_type)
+{
+    if (key == NULL || buffer == NULL || buffer_size == 0) {
+        tr_error("CloudClientStorage::ccs_get_item error, invalid parameters");
+        return CCS_STATUS_ERROR;
+    }
+
+    tr_debug("CloudClientStorage::ccs_get_item [%s], type [%d]", key, item_type);
+
+    kcm_status_e kcm_status = kcm_item_get_data((const uint8_t*)key,
+                                    strlen(key),
+                                    (kcm_item_type_e)item_type,
+                                    buffer,
+                                    buffer_size,
+                                    value_length);
+
+    if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_debug("CloudClientStorage::ccs_get_item [%s] kcm error %d", key, kcm_status);
+        return CCS_STATUS_ERROR;
+    }
+
+    return CCS_STATUS_SUCCESS;
+}
+
+ccs_status_e ccs_set_item(const char* key,
+                          const uint8_t *buffer,
+                          const size_t buffer_size,
+                          ccs_item_type_e item_type)
+{
+    if (key == NULL || buffer == NULL || buffer_size == 0) {
+        tr_error("CloudClientStorage::ccs_set_item error, invalid parameters");
+        return CCS_STATUS_ERROR;
+    }
+
+    tr_debug("CloudClientStorage::ccs_set_item kcm [%s], type [%d]", key, item_type);
+
+    kcm_status_e kcm_status = kcm_item_store((const uint8_t*)key,
+                                 strlen(key),
+                                 (kcm_item_type_e)item_type,
+                                 false,
+                                 buffer,
+                                 buffer_size,
+                                 NULL);
+
+    if (kcm_status == KCM_CRYPTO_STATUS_PRIVATE_KEY_VERIFICATION_FAILED) {
+        tr_error("CloudClientStorage::ccs_set_item kcm validation error");
+        return CCS_STATUS_VALIDATION_FAIL;
+    }
+    else if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_debug("CloudClientStorage::ccs_set_item kcm [%s] error %d", key, kcm_status);
+        return CCS_STATUS_ERROR;
+    }
+
+    return CCS_STATUS_SUCCESS;
+}
+
+void *ccs_create_certificate_chain(const char *chain_file_name, size_t chain_len)
+{
+    kcm_status_e kcm_status;
+    kcm_cert_chain_handle chain_handle;
+
+    kcm_status = kcm_cert_chain_create(&chain_handle,
+                                       (uint8_t*)chain_file_name,
+                                       strlen(chain_file_name),
+                                       chain_len,
+                                       false);
+
+    if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_error("CloudClientStorage::ccs_create_certificate_chain - error %d", kcm_status);
+        return NULL;
+    } else {
+        return (void*)chain_handle;
+    }
+}
+
+void *ccs_open_certificate_chain(const char *chain_file_name, size_t *chain_size)
+{
+    kcm_status_e kcm_status;
+    kcm_cert_chain_handle handle;
+
+    kcm_status = kcm_cert_chain_open(&handle,
+                                     (uint8_t*)chain_file_name,
+                                     strlen(chain_file_name),
+                                     chain_size);
+
+    if (kcm_status == KCM_STATUS_SUCCESS) {
+        return (void*)handle;
+    } else {
+        tr_error("CloudClientStorage::ccs_open_certificate_chain - error %d", kcm_status);
+        return NULL;
+    }
+}
+
+ccs_status_e ccs_get_next_cert_chain(void *chain_handle, void *cert_data, size_t *data_size)
+{
+    kcm_status_e kcm_status;
+    size_t max_size = 1024;
+
+    kcm_status = kcm_cert_chain_get_next_size((kcm_cert_chain_handle *) chain_handle, data_size);
+
+    if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_error("CloudClientStorage::ccs_get_next_cert_chain - get_next_size error %d", kcm_status);
+        return CCS_STATUS_ERROR;
+    }
+
+
+    kcm_status = kcm_cert_chain_get_next_data((kcm_cert_chain_handle *) chain_handle, (uint8_t*)cert_data, max_size, data_size);
+
+    if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_error("CloudClientStorage::ccs_get_next_cert_chain - get_next_data error %d", kcm_status);
+        return CCS_STATUS_ERROR;
+    } else {
+        return CCS_STATUS_SUCCESS;
+    }
+}
+
+ccs_status_e ccs_close_certificate_chain(void *chain_handle)
+{
+    kcm_status_e kcm_status;
+    kcm_cert_chain_handle *handle = (kcm_cert_chain_handle *) chain_handle;
+    kcm_status = kcm_cert_chain_close(handle);
+    if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_error("CloudClientStorage::ccs_close_certificate_chain - error %d", kcm_status);
+        return CCS_STATUS_ERROR;
+    } else {
+        return CCS_STATUS_SUCCESS;
+    }
+}
+
+ccs_status_e ccs_add_next_cert_chain(void *chain_handle, const uint8_t *cert_data, size_t data_size)
+{
+    kcm_status_e kcm_status;
+    kcm_status = kcm_cert_chain_add_next((kcm_cert_chain_handle *) chain_handle, cert_data, data_size);
+
+    if (kcm_status != KCM_STATUS_SUCCESS) {
+        tr_error("CloudClientStorage::ccs_add_next_cert_chain - error %d", kcm_status);
+        return CCS_STATUS_ERROR;
+    } else {
+        return CCS_STATUS_SUCCESS;
+    }
+}
+
+ccs_status_e ccs_parse_cert_chain_and_store(const uint8_t *cert_chain_name,
+                                            const size_t cert_chain_name_len,
+                                            const uint8_t *cert_chain_data,
+                                            const uint16_t cert_chain_data_len)
+{
+    assert(cert_chain_data);
+    assert(cert_chain_data_len > 0);
+
+    const uint8_t *ptr = cert_chain_data;
+    uint8_t version = *ptr++;
+    uint8_t chain_length = *ptr++;
+    ccs_status_e success = CCS_STATUS_SUCCESS;
+    kcm_cert_chain_handle chain_handle;
+    kcm_status_e status;
+
+    // Check overflow
+    if (ptr - cert_chain_data > cert_chain_data_len) {
+        success = CCS_STATUS_VALIDATION_FAIL;
+    }
+
+    // Check version is correct and there are certs in the chain
+    if (version != 1 || chain_length == 0) {
+        success = CCS_STATUS_VALIDATION_FAIL;
+    }
+
+    // Create KCM cert chain
+    if (success == CCS_STATUS_SUCCESS) {
+        status = kcm_cert_chain_create(&chain_handle,
+                                       cert_chain_name,
+                                       cert_chain_name_len,
+                                       chain_length,
+                                       false);
+        tr_debug("Cert chain create %d", status);
+        if (status != KCM_STATUS_SUCCESS) {
+            success = CCS_STATUS_ERROR;
+        }
+    }
+
+    if (success == CCS_STATUS_SUCCESS) {
+        for (uint8_t i = 0; i < chain_length; i++) {
+            // Parse certificate length (2 bytes)
+            uint16_t cert_len = common_read_16_bit(ptr);
+            ptr += 2;
+            // Check overflow
+            if (ptr - cert_chain_data > cert_chain_data_len) {
+                success = CCS_STATUS_VALIDATION_FAIL;
+                break;
+            }
+
+            // Store certificate
+            tr_debug("Storing cert\r\n%s", tr_array(ptr, cert_len));
+            status = kcm_cert_chain_add_next(chain_handle, ptr, cert_len);
+            if (status != KCM_STATUS_SUCCESS) {
+                success = CCS_STATUS_ERROR;
+                break;
+            }
+
+            ptr += cert_len;
+
+            // Check overflow
+            if (ptr - cert_chain_data > cert_chain_data_len) {
+                success = CCS_STATUS_VALIDATION_FAIL;
+                break;
+            }
+        }
+
+        status = kcm_cert_chain_close(chain_handle);
+        if (status != KCM_STATUS_SUCCESS) {
+            success = CCS_STATUS_ERROR;
+        }
+    }
+
+    if (success != CCS_STATUS_SUCCESS) {
+        kcm_cert_chain_delete(cert_chain_name, cert_chain_name_len);
+    }
+
+    return success;
+}