Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SecureStore.cpp Source File

SecureStore.cpp

00001 /*
00002  * Copyright (c) 2018 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 // ----------------------------------------------------------- Includes -----------------------------------------------------------
00018 
00019 #include "SecureStore.h"
00020 
00021 #if SECURESTORE_ENABLED
00022 
00023 #include "aes.h"
00024 #include "cmac.h"
00025 #include "mbedtls/platform.h"
00026 #include "entropy.h"
00027 #include "DeviceKey.h"
00028 #include "mbed_assert.h"
00029 #include "mbed_wait_api.h"
00030 #include "mbed_error.h"
00031 #include <algorithm>
00032 #include <string.h>
00033 #include <stdio.h>
00034 
00035 using namespace mbed;
00036 
00037 // --------------------------------------------------------- Definitions ----------------------------------------------------------
00038 
00039 static const uint32_t securestore_revision = 1;
00040 
00041 static const uint32_t enc_block_size    = 16;
00042 static const uint32_t cmac_size         = 16;
00043 static const uint32_t iv_size           = 8;
00044 static const uint32_t scratch_buf_size  = 256;
00045 static const uint32_t derived_key_size  = 16;
00046 
00047 static const char *const enc_prefix  = "ENC";
00048 static const char *const auth_prefix = "AUTH";
00049 
00050 static const uint32_t security_flags = KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG;
00051 
00052 namespace {
00053 typedef struct {
00054     uint16_t metadata_size = 0u;
00055     uint16_t revision = 0u;
00056     uint32_t data_size = 0u;
00057     uint32_t create_flags = 0u;
00058     uint8_t  iv[iv_size] = { 0u };
00059 } record_metadata_t;
00060 
00061 // iterator handle
00062 typedef struct {
00063     KVStore::iterator_t underlying_it;
00064 } key_iterator_handle_t;
00065 
00066 }
00067 
00068 // incremental set handle
00069 struct SecureStore::inc_set_handle_t {
00070     record_metadata_t metadata;
00071     char *key = nullptr;
00072     uint32_t offset_in_data = 0u;
00073     uint8_t ctr_buf[enc_block_size] = { 0u };
00074     mbedtls_aes_context enc_ctx;
00075     mbedtls_cipher_context_t auth_ctx;
00076     KVStore::set_handle_t underlying_handle;
00077 };
00078 
00079 // -------------------------------------------------- Local Functions Declaration ----------------------------------------------------
00080 
00081 // -------------------------------------------------- Functions Implementation ----------------------------------------------------
00082 
00083 int encrypt_decrypt_start(mbedtls_aes_context &enc_aes_ctx, uint8_t *iv, const char *key,
00084                           uint8_t *ctr_buf, uint8_t *salt_buf, int salt_buf_size)
00085 {
00086     DeviceKey &devkey = DeviceKey::get_instance();
00087     char *salt = reinterpret_cast<char *>(salt_buf);
00088     uint8_t encrypt_key[derived_key_size];
00089     strcpy(salt, enc_prefix);
00090     int pos = strlen(enc_prefix);
00091     strncpy(salt + pos, key, salt_buf_size - pos - 1);
00092     salt_buf[salt_buf_size - 1] = 0;
00093     int os_ret = devkey.generate_derived_key(salt_buf, strlen(salt), encrypt_key,  DEVICE_KEY_16BYTE);
00094     if (os_ret) {
00095         return os_ret;
00096     }
00097 
00098     mbedtls_aes_init(&enc_aes_ctx);
00099     mbedtls_aes_setkey_enc(&enc_aes_ctx, encrypt_key, enc_block_size * 8);
00100 
00101     memcpy(ctr_buf, iv, iv_size);
00102     memset(ctr_buf + iv_size, 0, iv_size);
00103 
00104     return 0;
00105 }
00106 
00107 int encrypt_decrypt_data(mbedtls_aes_context &enc_aes_ctx, const uint8_t *in_buf,
00108                          uint8_t *out_buf, uint32_t chunk_size, uint8_t *ctr_buf, size_t &aes_offs)
00109 {
00110     uint8_t stream_block[enc_block_size] = { 0 };
00111 
00112     return mbedtls_aes_crypt_ctr(&enc_aes_ctx, chunk_size, &aes_offs, ctr_buf,
00113                                  stream_block, in_buf, out_buf);
00114 }
00115 
00116 int cmac_calc_start(mbedtls_cipher_context_t &auth_ctx, const char *key, uint8_t *salt_buf, int salt_buf_size)
00117 {
00118     DeviceKey &devkey = DeviceKey::get_instance();
00119     char *salt = reinterpret_cast<char *>(salt_buf);
00120     uint8_t auth_key[derived_key_size];
00121     strcpy(salt, auth_prefix);
00122     int pos = strlen(auth_prefix);
00123     strncpy(salt + pos, key, salt_buf_size - pos - 1);
00124     salt_buf[salt_buf_size - 1] = 0;
00125     int os_ret = devkey.generate_derived_key(salt_buf, strlen(salt), auth_key, DEVICE_KEY_16BYTE);
00126     if (os_ret) {
00127         return os_ret;
00128     }
00129 
00130     const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB);
00131 
00132     mbedtls_cipher_init(&auth_ctx);
00133 
00134     if ((os_ret = mbedtls_cipher_setup(&auth_ctx, cipher_info)) != 0) {
00135         return os_ret;
00136     }
00137 
00138     os_ret = mbedtls_cipher_cmac_starts(&auth_ctx, auth_key, cmac_size * 8);
00139     if (os_ret != 0) {
00140         return os_ret;
00141     }
00142 
00143     return 0;
00144 }
00145 
00146 int cmac_calc_data(mbedtls_cipher_context_t &auth_ctx, const void *input, size_t ilen)
00147 {
00148     int os_ret;
00149 
00150     os_ret = mbedtls_cipher_cmac_update(&auth_ctx, static_cast<const uint8_t *>(input), ilen);
00151 
00152     return os_ret;
00153 }
00154 
00155 int cmac_calc_finish(mbedtls_cipher_context_t &auth_ctx, uint8_t *output)
00156 {
00157     int os_ret;
00158 
00159     os_ret = mbedtls_cipher_cmac_finish(&auth_ctx, output);
00160 
00161     return os_ret;
00162 }
00163 
00164 
00165 
00166 // Class member functions
00167 
00168 SecureStore::SecureStore(KVStore *underlying_kv, KVStore *rbp_kv) :
00169     _is_initialized(false), _underlying_kv(underlying_kv), _rbp_kv(rbp_kv), _entropy(0),
00170     _ih(0), _scratch_buf(0)
00171 {
00172 }
00173 
00174 SecureStore::~SecureStore()
00175 {
00176     deinit();
00177 }
00178 
00179 
00180 int SecureStore::set_start(set_handle_t *handle, const char *key, size_t final_data_size,
00181                            uint32_t create_flags)
00182 {
00183     int ret, os_ret;
00184     info_t info;
00185     bool enc_started = false, auth_started = false;
00186 
00187     if (!_is_initialized) {
00188         return MBED_ERROR_NOT_READY;
00189     }
00190 
00191     if (!is_valid_key(key)) {
00192         return MBED_ERROR_INVALID_ARGUMENT;
00193     }
00194 
00195     _mutex.lock();
00196     *handle = reinterpret_cast<set_handle_t>(_ih);
00197 
00198     // Validate internal RBP data
00199     if (_rbp_kv) {
00200         ret = _rbp_kv->get_info(key, &info);
00201         if (ret == MBED_SUCCESS) {
00202             if (info.flags & WRITE_ONCE_FLAG) {
00203                 // Trying to re-write a key that is write protected
00204                 ret = MBED_ERROR_WRITE_PROTECTED;
00205                 goto fail;
00206             }
00207             if (!(create_flags & REQUIRE_REPLAY_PROTECTION_FLAG)) {
00208                 // Trying to re-write a key that that has REPLAY_PROTECTION
00209                 // with a new key that has this flag not set.
00210                 ret = MBED_ERROR_INVALID_ARGUMENT;
00211                 goto fail;
00212             }
00213         } else if (ret != MBED_ERROR_ITEM_NOT_FOUND) {
00214             ret = MBED_ERROR_READ_FAILED;
00215             goto fail;
00216         }
00217     } else {
00218         // Only trust external flags, if internal RBP is not in use
00219         ret = _underlying_kv->get(key, &_ih->metadata, sizeof(record_metadata_t));
00220         if (ret == MBED_SUCCESS) {
00221             // Must not remove RP flag, even though internal RBP KV is not in use.
00222             if (!(create_flags & REQUIRE_REPLAY_PROTECTION_FLAG) && (_ih->metadata.create_flags & REQUIRE_REPLAY_PROTECTION_FLAG)) {
00223                 ret = MBED_ERROR_INVALID_ARGUMENT;
00224                 goto fail;
00225             }
00226             // Existing key is write protected
00227             if (_ih->metadata.create_flags & WRITE_ONCE_FLAG) {
00228                 ret = MBED_ERROR_WRITE_PROTECTED;
00229                 goto fail;
00230             }
00231         }
00232     }
00233 
00234     // Fill metadata
00235     _ih->metadata.create_flags = create_flags;
00236     _ih->metadata.data_size = final_data_size;
00237     _ih->metadata.metadata_size = sizeof(record_metadata_t);
00238     _ih->metadata.revision = securestore_revision;
00239 
00240     if (create_flags & REQUIRE_CONFIDENTIALITY_FLAG) {
00241         // generate a new random iv
00242         os_ret = mbedtls_entropy_func(_entropy, _ih->metadata.iv, iv_size);
00243         if (os_ret) {
00244             ret = MBED_ERROR_FAILED_OPERATION;
00245             goto fail;
00246         }
00247         os_ret = encrypt_decrypt_start(_ih->enc_ctx, _ih->metadata.iv, key, _ih->ctr_buf, _scratch_buf,
00248                                        scratch_buf_size);
00249         if (os_ret) {
00250             ret = MBED_ERROR_FAILED_OPERATION;
00251             goto fail;
00252         }
00253         enc_started = true;
00254     } else {
00255         memset(_ih->metadata.iv, 0, iv_size);
00256     }
00257 
00258     os_ret = cmac_calc_start(_ih->auth_ctx, key, _scratch_buf, scratch_buf_size);
00259     if (os_ret) {
00260         ret = MBED_ERROR_FAILED_OPERATION;
00261         goto fail;
00262     }
00263     auth_started = true;
00264     // Although name is not part of the data, we calculate CMAC on it as well
00265     os_ret = cmac_calc_data(_ih->auth_ctx, key, strlen(key));
00266     if (os_ret) {
00267         ret = MBED_ERROR_FAILED_OPERATION;
00268         goto fail;
00269     }
00270     os_ret = cmac_calc_data(_ih->auth_ctx, &_ih->metadata, sizeof(record_metadata_t));
00271     if (os_ret) {
00272         ret = MBED_ERROR_FAILED_OPERATION;
00273         goto fail;
00274     }
00275 
00276     _ih->offset_in_data = 0;
00277     _ih->key = 0;
00278 
00279     // Should strip security flags from underlying storage
00280     ret = _underlying_kv->set_start(&_ih->underlying_handle, key,
00281                                     sizeof(record_metadata_t) + final_data_size + cmac_size,
00282                                     create_flags & ~security_flags);
00283     if (ret) {
00284         goto fail;
00285     }
00286 
00287     ret = _underlying_kv->set_add_data(_ih->underlying_handle, &_ih->metadata,
00288                                        sizeof(record_metadata_t));
00289     if (ret) {
00290         goto fail;
00291     }
00292 
00293     if (create_flags & (REQUIRE_REPLAY_PROTECTION_FLAG | WRITE_ONCE_FLAG)) {
00294         _ih->key = new char[strlen(key) + 1];
00295         strcpy(_ih->key, key);
00296     }
00297 
00298     goto end;
00299 
00300 fail:
00301     if (enc_started) {
00302         mbedtls_aes_free(&_ih->enc_ctx);
00303     }
00304 
00305     if (auth_started) {
00306         mbedtls_cipher_free(&_ih->auth_ctx);
00307     }
00308 
00309     // mark handle as invalid by clearing metadata size field in header
00310     _ih->metadata.metadata_size = 0;
00311     _mutex.unlock();
00312 
00313 end:
00314     return ret;
00315 }
00316 
00317 int SecureStore::set_add_data(set_handle_t handle, const void *value_data, size_t data_size)
00318 {
00319     size_t aes_offs = 0;
00320     int os_ret, ret = MBED_SUCCESS;
00321     const uint8_t *src_ptr;
00322 
00323     if (reinterpret_cast<inc_set_handle_t *>(handle) != _ih) {
00324         return MBED_ERROR_INVALID_ARGUMENT;
00325     }
00326 
00327     if (!value_data && data_size) {
00328         return MBED_ERROR_INVALID_ARGUMENT;
00329     }
00330 
00331     if (!_ih->metadata.metadata_size) {
00332         return MBED_ERROR_INVALID_ARGUMENT;
00333     }
00334 
00335     if (_ih->offset_in_data + data_size > _ih->metadata.data_size) {
00336         ret = MBED_ERROR_INVALID_SIZE;
00337         goto end;
00338     }
00339 
00340     src_ptr = static_cast<const uint8_t *>(value_data);
00341     while (data_size) {
00342         uint32_t chunk_size;
00343         const uint8_t *dst_ptr;
00344         if (_ih->metadata.create_flags & REQUIRE_CONFIDENTIALITY_FLAG) {
00345             // In encrypt mode we don't want to allocate a buffer in the size given by the user -
00346             // Encrypt the data chunk by chunk
00347             chunk_size = std::min((uint32_t) data_size, scratch_buf_size);
00348             dst_ptr = _scratch_buf;
00349             os_ret = encrypt_decrypt_data(_ih->enc_ctx, src_ptr, _scratch_buf,
00350                                           chunk_size, _ih->ctr_buf, aes_offs);
00351             if (os_ret) {
00352                 ret = MBED_ERROR_FAILED_OPERATION;
00353                 goto fail;
00354             }
00355         } else {
00356             chunk_size = data_size;
00357             dst_ptr = static_cast <const uint8_t *>(value_data);
00358         }
00359 
00360         os_ret = cmac_calc_data(_ih->auth_ctx, dst_ptr, chunk_size);
00361         if (os_ret) {
00362             ret = MBED_ERROR_FAILED_OPERATION;
00363             goto fail;
00364         }
00365 
00366         ret = _underlying_kv->set_add_data(_ih->underlying_handle, dst_ptr, chunk_size);
00367         if (ret) {
00368             goto fail;
00369         }
00370         data_size -= chunk_size;
00371         src_ptr += chunk_size;
00372         _ih->offset_in_data += chunk_size;
00373     }
00374 
00375     goto end;
00376 
00377 fail:
00378     if (_ih->key) {
00379         delete[] _ih->key;
00380     }
00381     if (_ih->metadata.create_flags & REQUIRE_CONFIDENTIALITY_FLAG) {
00382         mbedtls_aes_free(&_ih->enc_ctx);
00383     }
00384 
00385     mbedtls_cipher_free(&_ih->auth_ctx);
00386 
00387     // mark handle as invalid by clearing metadata size field in header
00388     _ih->metadata.metadata_size = 0;
00389     _mutex.unlock();
00390 
00391 end:
00392     return ret;
00393 }
00394 
00395 int SecureStore::set_finalize(set_handle_t handle)
00396 {
00397     int os_ret, ret = MBED_SUCCESS;
00398     uint8_t cmac[cmac_size] = {0};
00399 
00400     if (reinterpret_cast<inc_set_handle_t *>(handle) != _ih) {
00401         return MBED_ERROR_INVALID_ARGUMENT;
00402     }
00403 
00404     if (!_ih->metadata.metadata_size) {
00405         return MBED_ERROR_INVALID_ARGUMENT;
00406     }
00407 
00408     if (_ih->offset_in_data != _ih->metadata.data_size) {
00409         ret = MBED_ERROR_INVALID_SIZE;
00410         goto end;
00411     }
00412 
00413     os_ret = cmac_calc_finish(_ih->auth_ctx, cmac);
00414     if (os_ret) {
00415         ret = MBED_ERROR_FAILED_OPERATION;
00416         goto end;
00417     }
00418 
00419     ret = _underlying_kv->set_add_data(_ih->underlying_handle, cmac, cmac_size);
00420     if (ret) {
00421         goto end;
00422     }
00423 
00424     ret = _underlying_kv->set_finalize(_ih->underlying_handle);
00425     if (ret) {
00426         goto end;
00427     }
00428 
00429     if (_rbp_kv && (_ih->metadata.create_flags & (REQUIRE_REPLAY_PROTECTION_FLAG | WRITE_ONCE_FLAG))) {
00430         // In rollback protect case, we need to store CMAC in RBP store.
00431         // If it's also write once case, set write once flag in the RBP key as well.
00432         // Use RBP storage also in write once case only - in order to prevent attacks removing
00433         // a written once value from underlying KV.
00434         ret = _rbp_kv->set(_ih->key, cmac, cmac_size, _ih->metadata.create_flags & WRITE_ONCE_FLAG);
00435         delete[] _ih->key;
00436         if (ret) {
00437             goto end;
00438         }
00439     }
00440 
00441 end:
00442     // mark handle as invalid by clearing metadata size field in header
00443     _ih->metadata.metadata_size = 0;
00444     if (_ih->metadata.create_flags & REQUIRE_CONFIDENTIALITY_FLAG) {
00445         mbedtls_aes_free(&_ih->enc_ctx);
00446     }
00447 
00448     mbedtls_cipher_free(&_ih->auth_ctx);
00449 
00450     _mutex.unlock();
00451     return ret;
00452 }
00453 
00454 int SecureStore::set(const char *key, const void *buffer, size_t size, uint32_t create_flags)
00455 {
00456     int ret;
00457     set_handle_t handle;
00458 
00459     // Don't wait till we get to set_add_data to catch this
00460     if (!buffer && size) {
00461         return MBED_ERROR_INVALID_ARGUMENT;
00462     }
00463 
00464     ret = set_start(&handle, key, size, create_flags);
00465     if (ret) {
00466         return ret;
00467     }
00468 
00469     ret = set_add_data(handle, buffer, size);
00470     if (ret) {
00471         return ret;
00472     }
00473 
00474     ret = set_finalize(handle);
00475     return ret;
00476 }
00477 
00478 int SecureStore::remove(const char *key)
00479 {
00480     info_t info;
00481     _mutex.lock();
00482 
00483     int ret = do_get(key, 0, 0, 0, 0, &info);
00484     // Allow deleting key if read error is of our own errors
00485     if ((ret != MBED_SUCCESS) && (ret != MBED_ERROR_AUTHENTICATION_FAILED) &&
00486             (ret != MBED_ERROR_RBP_AUTHENTICATION_FAILED)) {
00487         goto end;
00488     }
00489 
00490     if (ret == 0 && info.flags & WRITE_ONCE_FLAG) {
00491         ret = MBED_ERROR_WRITE_PROTECTED;
00492         goto end;
00493     }
00494 
00495     ret = _underlying_kv->remove(key);
00496     if (ret) {
00497         goto end;
00498     }
00499 
00500     if (_rbp_kv && (info.flags & REQUIRE_REPLAY_PROTECTION_FLAG)) {
00501         ret = _rbp_kv->remove(key);
00502         if ((ret != MBED_SUCCESS) && (ret != MBED_ERROR_ITEM_NOT_FOUND)) {
00503             goto end;
00504         }
00505     }
00506 
00507     ret = MBED_SUCCESS;
00508 
00509 end:
00510     _mutex.unlock();
00511     return ret;
00512 }
00513 
00514 int SecureStore::do_get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size,
00515                         size_t offset, info_t *info)
00516 {
00517     int os_ret, ret;
00518     bool rbp_key_exists = false;
00519     uint8_t rbp_cmac[cmac_size];
00520     size_t aes_offs = 0;
00521     uint32_t data_size;
00522     uint32_t actual_data_size;
00523     uint32_t current_offset;
00524     uint32_t chunk_size;
00525     uint32_t enc_lead_size;
00526     uint8_t *dest_buf;
00527     bool enc_started = false, auth_started = false;
00528     uint32_t create_flags;
00529     size_t read_len;
00530     info_t rbp_info;
00531 
00532     if (!is_valid_key(key)) {
00533         return MBED_ERROR_INVALID_ARGUMENT;
00534     }
00535 
00536     if (_rbp_kv) {
00537         ret = _rbp_kv->get_info(key, &rbp_info);
00538         if (ret == MBED_SUCCESS) {
00539             rbp_key_exists = true;
00540             ret = _rbp_kv->get(key, rbp_cmac, cmac_size, &read_len);
00541             if (ret) {
00542                 goto end;
00543             }
00544             if ((read_len != cmac_size) || (rbp_info.size != cmac_size)) {
00545                 ret = MBED_ERROR_RBP_AUTHENTICATION_FAILED;
00546             }
00547         } else if (ret != MBED_ERROR_ITEM_NOT_FOUND) {
00548             goto end;
00549         }
00550     }
00551 
00552     ret = _underlying_kv->get(key, &_ih->metadata, sizeof(record_metadata_t), &read_len);
00553     if (ret) {
00554         // In case we have the key in the RBP KV, then even if the key wasn't found in
00555         // the underlying KV, we may have been exposed to an attack. Return an RBP authentication error.
00556         if (rbp_key_exists) {
00557             ret = MBED_ERROR_RBP_AUTHENTICATION_FAILED;
00558         }
00559         goto end;
00560     }
00561 
00562     // Validate header size
00563     if ((read_len != sizeof(record_metadata_t))  || (_ih->metadata.metadata_size != sizeof(record_metadata_t))) {
00564         ret = MBED_ERROR_RBP_AUTHENTICATION_FAILED;
00565         goto end;
00566     }
00567 
00568     create_flags = _ih->metadata.create_flags;
00569     if (!_rbp_kv) {
00570         create_flags &= ~REQUIRE_REPLAY_PROTECTION_FLAG;
00571     }
00572 
00573     // Another potential attack case - key hasn't got the RP flag set, but exists in the RBP KV
00574     if (rbp_key_exists && !(create_flags & (REQUIRE_REPLAY_PROTECTION_FLAG |  WRITE_ONCE_FLAG))) {
00575         ret = MBED_ERROR_RBP_AUTHENTICATION_FAILED;
00576         goto end;
00577     }
00578 
00579     os_ret = cmac_calc_start(_ih->auth_ctx, key, _scratch_buf, scratch_buf_size);
00580     if (os_ret) {
00581         ret = MBED_ERROR_FAILED_OPERATION;
00582         goto end;
00583     }
00584     auth_started = true;
00585 
00586     // Although name is not part of the data, we calculate CMAC on it as well
00587     os_ret = cmac_calc_data(_ih->auth_ctx, key, strlen(key));
00588     if (os_ret) {
00589         ret = MBED_ERROR_FAILED_OPERATION;
00590         goto end;
00591     }
00592     os_ret = cmac_calc_data(_ih->auth_ctx, &_ih->metadata, sizeof(record_metadata_t));
00593     if (os_ret) {
00594         ret = MBED_ERROR_FAILED_OPERATION;
00595         goto end;
00596     }
00597 
00598     if (create_flags & REQUIRE_CONFIDENTIALITY_FLAG) {
00599         os_ret = encrypt_decrypt_start(_ih->enc_ctx, _ih->metadata.iv, key, _ih->ctr_buf, _scratch_buf,
00600                                        scratch_buf_size);
00601         if (os_ret) {
00602             ret = MBED_ERROR_FAILED_OPERATION;
00603             goto end;
00604         }
00605         enc_started = true;
00606     }
00607 
00608     data_size = _ih->metadata.data_size;
00609     actual_data_size = std::min((uint32_t) buffer_size, data_size - offset);
00610     current_offset = 0;
00611     enc_lead_size = 0;
00612 
00613     while (data_size) {
00614         // Make sure we read to the user buffer only between offset and offset + actual_data_size
00615         if ((current_offset >= offset) && (current_offset < offset + actual_data_size)) {
00616             dest_buf = (static_cast <uint8_t *>(buffer)) + enc_lead_size;
00617             chunk_size = actual_data_size - enc_lead_size;
00618             enc_lead_size = 0;
00619         } else {
00620             dest_buf = _scratch_buf;
00621             if (current_offset < offset) {
00622                 chunk_size = std::min(scratch_buf_size, offset - current_offset);
00623                 // A special case: encrypted user data starts at a middle of an encryption block.
00624                 // In this case, we need to read entire block into our scratch buffer, and copy
00625                 // the encrypted lead size to the user buffer start
00626                 if ((create_flags & REQUIRE_CONFIDENTIALITY_FLAG) &&
00627                         (chunk_size % enc_block_size)) {
00628                     enc_lead_size = std::min(enc_block_size - chunk_size % enc_block_size, actual_data_size);
00629                     chunk_size += enc_lead_size;
00630                 }
00631             } else {
00632                 chunk_size = std::min(scratch_buf_size, data_size);
00633                 enc_lead_size = 0;
00634             }
00635         }
00636 
00637         ret = _underlying_kv->get(key, dest_buf, chunk_size, 0,
00638                                   _ih->metadata.metadata_size + current_offset);
00639         if (ret != MBED_SUCCESS) {
00640             goto end;
00641         }
00642 
00643         os_ret = cmac_calc_data(_ih->auth_ctx, dest_buf, chunk_size);
00644         if (os_ret) {
00645             ret = MBED_ERROR_FAILED_OPERATION;
00646             goto end;
00647         }
00648 
00649         if (create_flags & REQUIRE_CONFIDENTIALITY_FLAG) {
00650             // Decrypt data in place
00651             os_ret = encrypt_decrypt_data(_ih->enc_ctx, dest_buf, dest_buf, chunk_size, _ih->ctr_buf,
00652                                           aes_offs);
00653             if (os_ret) {
00654                 ret = MBED_ERROR_FAILED_OPERATION;
00655                 goto end;
00656             }
00657 
00658             if (enc_lead_size) {
00659                 // Now copy decrypted lead size to user buffer start
00660                 memcpy(buffer, dest_buf + chunk_size - enc_lead_size, enc_lead_size);
00661             }
00662         }
00663 
00664         current_offset += chunk_size;
00665         data_size -= chunk_size;
00666     }
00667 
00668     if (actual_size) {
00669         *actual_size = actual_data_size;
00670     }
00671 
00672     uint8_t calc_cmac[cmac_size], read_cmac[cmac_size];
00673     os_ret = cmac_calc_finish(_ih->auth_ctx, calc_cmac);
00674     if (os_ret) {
00675         ret = MBED_ERROR_FAILED_OPERATION;
00676         goto end;
00677     }
00678 
00679     // Check with record CMAC
00680     ret = _underlying_kv->get(key, read_cmac, cmac_size, 0,
00681                               _ih->metadata.metadata_size + _ih->metadata.data_size);
00682     if (ret) {
00683         goto end;
00684     }
00685     if (memcmp(calc_cmac, read_cmac, cmac_size) != 0) {
00686         ret = MBED_ERROR_AUTHENTICATION_FAILED;
00687         goto end;
00688     }
00689 
00690     // If rollback protect, check also CMAC stored in RBP store
00691     if (_rbp_kv && (create_flags & (REQUIRE_REPLAY_PROTECTION_FLAG | WRITE_ONCE_FLAG))) {
00692         if (!rbp_key_exists) {
00693             ret = MBED_ERROR_RBP_AUTHENTICATION_FAILED;
00694             goto end;
00695         }
00696         if (memcmp(calc_cmac, rbp_cmac, cmac_size) != 0) {
00697             ret = MBED_ERROR_RBP_AUTHENTICATION_FAILED;
00698             goto end;
00699         }
00700     }
00701 
00702     if (info) {
00703         info->flags = _ih->metadata.create_flags;
00704         info->size = _ih->metadata.data_size;
00705     }
00706 
00707 end:
00708     _ih->metadata.metadata_size = 0;
00709 
00710     if (enc_started) {
00711         mbedtls_aes_free(&_ih->enc_ctx);
00712     }
00713 
00714     if (auth_started) {
00715         mbedtls_cipher_free(&_ih->auth_ctx);
00716     }
00717 
00718     return ret;
00719 }
00720 
00721 int SecureStore::get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size,
00722                      size_t offset)
00723 {
00724     _mutex.lock();
00725     int ret = do_get(key, buffer, buffer_size, actual_size, offset);
00726     _mutex.unlock();
00727 
00728     return ret;
00729 }
00730 
00731 int SecureStore::get_info(const char *key, info_t *info)
00732 {
00733     _mutex.lock();
00734     int ret = do_get(key, 0, 0, 0, 0, info);
00735     _mutex.unlock();
00736 
00737     return ret;
00738 }
00739 
00740 
00741 int SecureStore::init()
00742 {
00743     int ret = MBED_SUCCESS;
00744 
00745     MBED_ASSERT(!(scratch_buf_size % enc_block_size));
00746     if (scratch_buf_size % enc_block_size) {
00747         return MBED_SYSTEM_ERROR_BASE;
00748     }
00749 
00750     _mutex.lock();
00751 #if defined(MBEDTLS_PLATFORM_C)
00752     ret = mbedtls_platform_setup(NULL);
00753     if (ret) {
00754         goto fail;
00755     }
00756 #endif /* MBEDTLS_PLATFORM_C */
00757 
00758     _entropy = new mbedtls_entropy_context;
00759     mbedtls_entropy_init(_entropy);
00760 
00761     _scratch_buf = new uint8_t[scratch_buf_size];
00762     _ih = new inc_set_handle_t;
00763 
00764     ret = _underlying_kv->init();
00765     if (ret) {
00766         goto fail;
00767     }
00768 
00769     if (_rbp_kv) {
00770         ret = _rbp_kv->init();
00771         if (ret) {
00772             goto fail;
00773         }
00774     }
00775 
00776     _is_initialized = true;
00777 
00778 fail:
00779     _mutex.unlock();
00780     return ret;
00781 }
00782 
00783 int SecureStore::deinit()
00784 {
00785     _mutex.lock();
00786     int ret;
00787     if (_is_initialized) {
00788         if (_entropy) {
00789             mbedtls_entropy_free(_entropy);
00790             delete _entropy;
00791             delete _ih;
00792             delete _scratch_buf;
00793             _entropy = nullptr;
00794         }
00795         ret = _underlying_kv->deinit();
00796         if (ret) {
00797             goto END;
00798         }
00799         if (_rbp_kv) {
00800             ret = _rbp_kv->deinit();
00801             if (ret) {
00802                 goto END;
00803             }
00804         }
00805     }
00806 
00807     _is_initialized = false;
00808 #if defined(MBEDTLS_PLATFORM_C)
00809     mbedtls_platform_teardown(NULL);
00810 #endif /* MBEDTLS_PLATFORM_C */
00811     ret = MBED_SUCCESS;
00812 END:
00813     _mutex.unlock();
00814 
00815     return ret;
00816 }
00817 
00818 
00819 int SecureStore::reset()
00820 {
00821     int ret;
00822 
00823     if (!_is_initialized) {
00824         return MBED_ERROR_NOT_READY;
00825     }
00826 
00827     _mutex.lock();
00828     ret = _underlying_kv->reset();
00829     if (ret) {
00830         goto end;
00831     }
00832 
00833     if (_rbp_kv) {
00834         ret = _rbp_kv->reset();
00835         if (ret) {
00836             goto end;
00837         }
00838     }
00839 
00840 end:
00841     _mutex.unlock();
00842     return ret;
00843 }
00844 
00845 int SecureStore::iterator_open(iterator_t *it, const char *prefix)
00846 {
00847     key_iterator_handle_t *handle;
00848 
00849     if (!_is_initialized) {
00850         return MBED_ERROR_NOT_READY;
00851     }
00852 
00853     if (!it) {
00854         return MBED_ERROR_INVALID_ARGUMENT;
00855     }
00856 
00857     handle = new key_iterator_handle_t;
00858     *it = reinterpret_cast<iterator_t>(handle);
00859 
00860     return _underlying_kv->iterator_open(&handle->underlying_it, prefix);
00861 }
00862 
00863 int SecureStore::iterator_next(iterator_t it, char *key, size_t key_size)
00864 {
00865     key_iterator_handle_t *handle;
00866 
00867     if (!_is_initialized) {
00868         return MBED_ERROR_NOT_READY;
00869     }
00870 
00871     handle = reinterpret_cast<key_iterator_handle_t *>(it);
00872 
00873     return _underlying_kv->iterator_next(handle->underlying_it, key, key_size);
00874 }
00875 
00876 int SecureStore::iterator_close(iterator_t it)
00877 {
00878     key_iterator_handle_t *handle;
00879     int ret;
00880 
00881     if (!_is_initialized) {
00882         return MBED_ERROR_NOT_READY;
00883     }
00884 
00885     handle = reinterpret_cast<key_iterator_handle_t *>(it);
00886 
00887     ret = _underlying_kv->iterator_close(handle->underlying_it);
00888 
00889     delete handle;
00890 
00891     return ret;
00892 }
00893 
00894 #endif