Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_mmInit.c Source File

arm_uc_mmInit.c

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #include "arm_uc_mmInit.h"
00020 #include "arm_uc_mmCommon.h"
00021 #if !MANIFEST_MANAGER_NO_STORAGE
00022 #include "update-client-manifest-manager/update-client-manifest-manager-context.h"
00023 #include "arm_uc_mmGetLatestTimestamp.h"
00024 #include "arm_uc_mm_derparse.h"
00025 #include "cfstore-fsm.h"
00026 #include "crypto-fsm.h"
00027 #include "accessors.h"
00028 #include "update-client-common/arm_uc_types.h"
00029 #include "update-client-common/arm_uc_common.h"
00030 #include "update-client-common/arm_uc_error.h"
00031 #include "mbedtls/sha256.h"
00032 
00033 #include "arm_uc_mmFSMHelper.h"
00034 
00035 #ifndef min
00036 #define min(X,Y) ((X) < (Y) ? (X) : (Y))
00037 #endif
00038 
00039 const char* ARM_UC_mmInitState2Str(uint32_t state)
00040 {
00041     switch (state) {
00042         #define ENUM_AUTO(name) case name: return #name;
00043         #define ENUM_FIXED(name, val) ENUM_AUTO(name)
00044         ARM_UC_MM_INIT_STATE_LIST
00045         #undef ENUM_FIXED
00046         #undef ENUM_AUTO
00047     default:
00048         return "Unknown State";
00049     }
00050 }
00051 
00052 
00053 
00054 arm_uc_error_t arm_uc_mmInitFSM(uint32_t event)
00055 {
00056     if (arm_uc_mmPersistentContext.ctx == NULL || *arm_uc_mmPersistentContext.ctx == NULL)
00057     {
00058         return (arm_uc_error_t){MFST_ERR_NULL_PTR};
00059     }
00060     struct arm_uc_mmInitContext_t* ctx = &(*arm_uc_mmPersistentContext.ctx)->init;
00061     arm_uc_error_t err = {MFST_ERR_PENDING};
00062 
00063     ARM_UC_MM_FSM_HELPER_START(*ctx, ARM_UC_mmInitState2Str){
00064     case ARM_UC_MM_INIT_BEGIN:
00065         // Find the latest manifest.
00066         ARM_UC_MM_SET_BUFFER(ctx->keyPath, ctx->pathBuffer);
00067         err = getLatestManifestTimestamp(&ctx->timestamp, &ctx->keyPath);
00068         ctx->state = ARM_UC_MM_INIT_LATEST_MFST;
00069         // clear the missing dep flag
00070         ctx->missingDep = 0;
00071         // Set the root manifest flag
00072         ctx->root = 1;
00073 
00074         event = ARM_UC_MM_EVENT_BEGIN;
00075         break;
00076     case ARM_UC_MM_INIT_LATEST_MFST:
00077     {
00078         err = getLatestManifestTimestampFSM(event);
00079         if (err.code != MFST_ERR_NONE)
00080         {
00081             break;
00082         }
00083         if (ctx->timestamp == 0)
00084         {
00085             err.code = MFST_ERR_NO_MANIFEST;
00086             break;
00087         }
00088         // Copy out the root manifest's base path
00089         strncpy((char*)ctx->rootManifestBasePath, (char*)ctx->keyPath.ptr, sizeof(ctx->rootManifestBasePath)-1);
00090         ctx->rootManifestBasePath[sizeof(ctx->rootManifestBasePath)-1] = 0;
00091         // Modify the key path.
00092         char* pos = (char*)ctx->keyPath.ptr + strlen((char*)ctx->keyPath.ptr) - strlen("ts");
00093         *pos = 'm';
00094         *(pos + 1) = 0;
00095         // Setup the manifest buffer
00096         ARM_UC_MM_SET_BUFFER(ctx->manifest, ctx->manifestBuffer);
00097         // Find the manifest
00098         err = ARM_UC_mmCfStoreFindKey(&ctx->keyPath);
00099         if (err.code != MFST_ERR_NONE)
00100         {
00101             break;
00102         }
00103         event = ARM_UC_MM_EVENT_CF_BEGIN;
00104         ctx->state = ARM_UC_MM_INIT_FINDING;
00105         // no break;
00106     }
00107     case ARM_UC_MM_INIT_FINDING:
00108         if (event == UCMM_EVENT_CF_FIND_FAILED)
00109         {
00110             if (ctx->root)
00111             {
00112                 //TODO: assert! This should not be possible!
00113                 err.code = MFST_ERR_INVALID_STATE;
00114             } else {
00115                 // No more deps to find.
00116                 err.code = MFST_ERR_NONE;
00117             }
00118             break;
00119         }
00120         err = ARM_UC_mmCfStoreFindKeyFSM(event);
00121         if (err.code != MFST_ERR_NONE)
00122         {
00123             break;
00124         }
00125         // Read the manifest
00126         err = ARM_UC_mmCfStoreReadLastKey(&ctx->manifest);
00127         if (err.code != MFST_ERR_NONE) {
00128             break;
00129         }
00130         event = ARM_UC_MM_EVENT_CF_BEGIN;
00131         ctx->state = ARM_UC_MM_INIT_READING;
00132         // no break;
00133     case ARM_UC_MM_INIT_READING:
00134         // Read the manifest into a buffer
00135         err = ARM_UC_mmCfStoreReadLastKeyFSM(event);
00136         if (err.code != MFST_ERR_NONE)
00137         {
00138             break;
00139         }
00140         ctx->state = ARM_UC_MM_INIT_STATE_HASH_VERIFY;
00141         // Preserve the manifest key
00142         ARM_UC_mmCfStorePreserveLastKey();
00143 
00144         // no break;
00145     case ARM_UC_MM_INIT_STATE_HASH_VERIFY:
00146         // Verify the manifest hash
00147         err = ucmmValidateManifestHash(&ctx->manifest);
00148         if (err.code == MFST_ERR_NONE) {
00149             uint32_t val;
00150             err = ARM_UC_mmGetCryptoMode(&ctx->manifest, &val);
00151             if (err.code != MFST_ERR_NONE)
00152             {
00153                 break;
00154             }
00155             ucmm_crypto_flags_t cryptoMode = ARM_UC_mmGetCryptoFlags(val);
00156             if(cryptoMode.ecc || cryptoMode.rsa) {
00157                 ctx->state = ARM_UC_MM_INIT_STATE_PK_VERIFY;
00158             } else {
00159                 ctx->state = ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN;
00160             }
00161         }
00162         break;
00163     case ARM_UC_MM_INIT_STATE_PK_VERIFY:
00164         // Verify the manifest signature
00165         err = ucmmValidateSignature(&ctx->manifest);
00166         if (err.code == MFST_ERR_NONE)
00167         {
00168             ctx->state = ARM_UC_MM_INIT_STATE_PK_VERIFYING;
00169         }
00170         break;
00171     case ARM_UC_MM_INIT_STATE_PK_VERIFYING:
00172         err = ucmmValidateSignatureFSM(event);
00173         if (err.code == MFST_ERR_NONE)
00174         {
00175             ctx->state = ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN;
00176         }
00177         break;
00178     case ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN:
00179     // ATTACKVECTOR: If an attacker can add a manifest to the dependency prefix in the config store, the manifest
00180     // manager has no way to know that it is not valid, due to the flat file heirarchy.
00181         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_MANIFEST_BEGIN;
00182         // NO BREAK;
00183     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_MANIFEST_BEGIN:
00184         // Loop: manifest
00185             // Set the depidx to 0
00186         ctx->depidx = 0;
00187         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH;
00188         // NO BREAK;
00189     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH:
00190     {
00191         arm_uc_buffer_t dependency;
00192         arm_uc_buffer_t hash;
00193         // Read the dependency at depidx
00194         err = ARM_UC_mmGetManifestLinksElement(&ctx->manifest, ctx->depidx, &dependency);
00195         // If there isn't one
00196         if (err.code != MFST_ERR_NONE)
00197         {
00198             break;
00199         }
00200         if (dependency.ptr == NULL)
00201         {
00202             // Exit Loop: dependency
00203             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_END;
00204             err.code = MFST_ERR_NONE;
00205             break;
00206         }
00207         // Get the dependency hash
00208         err = ARM_UC_mmGetManifestLinksHash(&dependency, &hash);
00209         if (err.code != MFST_ERR_NONE)
00210         {
00211             break;
00212         }
00213         // Store the dependency hash
00214         memcpy(ctx->currentHash, hash.ptr, min(hash.size, sizeof(ctx->currentHash)));
00215         // Format the dependency search key
00216         // The result of this operation is:
00217         // com.arm.mbed.update.mm.m.<root manifest hash>.deps.<dependency hash>.m
00218         // ASSUMES sizeof keypath > sizeof rootManifestBasePath
00219         strncpy((char*)ctx->keyPath.ptr, (char*)ctx->rootManifestBasePath, sizeof(ctx->keyPath.ptr));
00220         ctx->keyPath.size = strlen(ctx->keyPath.ptr);
00221         // Back up one space to remove the 'm'
00222         strncpy((char*)ctx->keyPath.ptr + ctx->keyPath.size-1, "deps.", ctx->keyPath.size_max - ctx->keyPath.size);
00223         ctx->keyPath.size = strlen(ctx->keyPath.ptr);
00224         ARM_UC_Base64Enc(ctx->keyPath.ptr + ctx->keyPath.size, ctx->keyPath.size_max - ctx->keyPath.size, &hash);
00225         ctx->keyPath.size = strlen(ctx->keyPath.ptr);
00226         strncpy((char*)ctx->keyPath.ptr + ctx->keyPath.size, ".m", ctx->keyPath.size_max - ctx->keyPath.size);
00227         ctx->keyPath.size += 3; // add one for null terminator
00228 
00229         // Find the dependency in the config store
00230         err = ucmmCfstoreFindAndRead((char*)ctx->keyPath.ptr, &ctx->manifest);
00231         if (err.code == MFST_ERR_NONE)
00232         {
00233             event = ARM_UC_MM_EVENT_BEGIN;
00234             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_READING_DEPENDENCY;
00235         }
00236         break;
00237     }
00238     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_READING_DEPENDENCY:
00239         // If there is no matching dependency
00240         if (event == UCMM_EVENT_CF_FIND_FAILED)
00241         {
00242             // Set the missing dep flag
00243             ctx->missingDep = 1;
00244             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK;
00245             // Continue...
00246             err.code = MFST_ERR_NONE;
00247             break;
00248         }
00249         // Find/Read the dependency manifest
00250         err = ucmmCfstoreFindAndReadFSM(event);
00251         if (err.code != MFST_ERR_NONE)
00252         {
00253             break;
00254         }
00255         // There is a matching dependency
00256         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_CHECK_HASH;
00257         // No break;
00258     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_CHECK_HASH:
00259     {
00260 #if MAX_HASH_BYTES != 256/8
00261 #error Hash size mismatch
00262 #endif
00263         uint8_t localhash[MAX_HASH_BYTES];
00264         arm_uc_buffer_t local = {
00265             .size_max = MAX_HASH_BYTES,
00266             .size     = 256/8,
00267             .ptr      = localhash
00268         };
00269         arm_uc_buffer_t resource;
00270         const int32_t valueID = ARM_UC_MM_DER_RESOURCE;
00271         int rc = ARM_UC_mmDERGetSignedResourceValues(&resource, 1, &valueID, &resource);
00272         if (rc)
00273         {
00274             err.code = MFST_ERR_DER_FORMAT;
00275             break;
00276         }
00277         {
00278             // Calculate the dependency hash
00279             mbedtls_sha256_context ctx;
00280             mbedtls_sha256_init(&ctx);
00281             mbedtls_sha256_starts(&ctx, 0);
00282             mbedtls_sha256_update(&ctx, resource.ptr, resource.size);
00283             mbedtls_sha256_finish(&ctx, local.ptr);
00284         }
00285         {
00286             arm_uc_buffer_t remote = {
00287                 .size_max = MAX_HASH_BYTES,
00288                 .size     = 256/8,
00289                 .ptr      = ctx->currentHash
00290             };
00291             // Validate the dependency hash
00292             if(ARM_UC_BinCompareCT(&local, &remote))
00293             {
00294                 // If invalid, Set the missing dep flag
00295                 ctx->missingDep = 1;
00296                 // Delete the manifest
00297                 ARM_UC_mmCfStoreDeleteLastKey();
00298                 ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_DELETE;
00299                 event = ARM_UC_MM_EVENT_CF_BEGIN;
00300             }
00301             else
00302             {
00303                 // End Loop: dependency
00304                 ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ;
00305                 // Increment the depidx
00306                 ctx->depidx++;
00307             }
00308         }
00309         break;
00310     }
00311     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_DELETE:
00312         err = ARM_UC_mmCfStoreDeleteLastKeyFSM(event);
00313         if (err.code == MFST_ERR_NONE)
00314         {
00315             // Make sure a URI exists.
00316             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK;
00317         }
00318         break;
00319     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK:
00320     {
00321         // modify the search path
00322         char* pos = (char*)ctx->keyPath.ptr + ctx->keyPath.size - 2; // null terminator
00323         strncpy(pos, "uri", ctx->keyPath.size_max - (ctx->keyPath.size - 2)); // null terminator
00324         // Check if there is a URI entry
00325         // HACK: No API for find without ovewriting the existing stored key. Use find/read even though we don't need the
00326         // data.
00327         err = ucmmCfstoreFindAndRead((char*)ctx->keyPath.ptr, &ctx->manifest);
00328         if (err.code != MFST_ERR_NONE)
00329         {
00330             break;
00331         }
00332         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECKING;
00333         event = ARM_UC_MM_EVENT_CF_BEGIN;
00334         // no break
00335     }
00336     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECKING:
00337         if (event == UCMM_EVENT_CF_FIND_FAILED)
00338         {
00339             // TODO: Erase all deps and start over.
00340             err.code = MFST_ERR_INVALID_STATE;
00341             break;
00342         }
00343         err = ucmmCfstoreFindAndReadFSM(event);
00344         if (err.code == MFST_ERR_NONE)
00345         {
00346             // Increment the depidx
00347             ctx->depidx++;
00348             // End Loop: dependency
00349             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ;
00350         }
00351         break;
00352     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ:
00353             // Loop: dependency
00354         // Restore the manifest key
00355         ARM_UC_mmCfStoreRestoreLastKey();
00356         // Seek the current key
00357         err = ARM_UC_mmCfStoreSeekLastKey(0);
00358         if (err.code == MFST_ERR_NONE)
00359         {
00360             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_SEEKING;
00361         }
00362         break;
00363     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_SEEKING:
00364         err = ARM_UC_mmCfStoreSeekLastKeyFSM(event);
00365         if (err.code != MFST_ERR_NONE)
00366         {
00367             break;
00368         }
00369         // Read the current key
00370         err = ARM_UC_mmCfStoreReadLastKey(&ctx->manifest);
00371         if (err.code != MFST_ERR_NONE)
00372         {
00373             break;
00374         }
00375         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READING;
00376         event = ARM_UC_MM_EVENT_CF_BEGIN;
00377         // no break
00378     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READING:
00379         err = ARM_UC_mmCfStoreReadLastKeyFSM(event);
00380         if (err.code == MFST_ERR_NONE)
00381         {
00382             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH;
00383             // Preserve the manifest key
00384             ARM_UC_mmCfStorePreserveLastKey();
00385         }
00386         break;
00387     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_END:
00388         // Format the dependency search key
00389         strncpy((char*)ctx->keyPath.ptr, (char*)ctx->rootManifestBasePath, sizeof(ctx->rootManifestBasePath));
00390         ctx->keyPath.size = sizeof(ctx->rootManifestBasePath)-1;
00391         strncpy((char*)ctx->keyPath.ptr + ctx->keyPath.size, ".deps.*", ctx->keyPath.size_max - ctx->keyPath.size);
00392         ctx->keyPath.size += sizeof(".deps.*") - 1;
00393         // If the root flag is set
00394         if (ctx->root)
00395         {
00396             // Clear the root flag
00397             ctx->root = 0;
00398             // Start the dependency search
00399             err = ARM_UC_mmCfStoreFindKey(&ctx->keyPath);
00400         }
00401         else
00402         {
00403             // Continue the dependency search
00404             err = ARM_UC_mmCfStoreFindNextKey();
00405         }
00406         if (err.code == MFST_ERR_NONE)
00407         {
00408             event = ARM_UC_MM_EVENT_CF_BEGIN;
00409             // End Loop: manifest
00410             ctx->state = ARM_UC_MM_INIT_FINDING;
00411         }
00412         break;
00413     default:
00414         err.code = MFST_ERR_INVALID_STATE;
00415         break;
00416     } ARM_UC_MM_FSM_HELPER_FINISH(*ctx);
00417     if (err.code == MFST_ERR_NONE && ctx->missingDep == 1)
00418     {
00419         // TODO: Configure & trigger insert FSM
00420     }
00421     return err;
00422 }
00423 
00424 #endif // !MANIFEST_MANAGER_NO_STORAGE