leo hendrickson / Mbed OS example-Ethernet-mbed-Cloud-connect
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 "update-client-metadata-header/arm_uc_buffer_utilities.h"
00032 #include "mbedtls/sha256.h"
00033 
00034 #include "arm_uc_mmFSMHelper.h"
00035 
00036 #ifndef min
00037 #define min(X,Y) ((X) < (Y) ? (X) : (Y))
00038 #endif
00039 
00040 const char *ARM_UC_mmInitState2Str(uint32_t state)
00041 {
00042     switch (state) {
00043 #define ENUM_AUTO(name) case name: return #name;
00044 #define ENUM_FIXED(name, val) ENUM_AUTO(name)
00045             ARM_UC_MM_INIT_STATE_LIST
00046 #undef ENUM_FIXED
00047 #undef ENUM_AUTO
00048         default:
00049             return "Unknown State";
00050     }
00051 }
00052 
00053 
00054 
00055 arm_uc_error_t arm_uc_mmInitFSM(uint32_t event)
00056 {
00057     if (arm_uc_mmPersistentContext.ctx == NULL || *arm_uc_mmPersistentContext.ctx == NULL) {
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             err = getLatestManifestTimestampFSM(event);
00078             if (err.code != ERR_NONE) {
00079                 break;
00080             }
00081             if (ctx->timestamp == 0) {
00082                 err.code = MFST_ERR_NO_MANIFEST;
00083                 break;
00084             }
00085             // Copy out the root manifest's base path
00086             strncpy((char *)ctx->rootManifestBasePath, (char *)ctx->keyPath.ptr, sizeof(ctx->rootManifestBasePath) - 1);
00087             ctx->rootManifestBasePath[sizeof(ctx->rootManifestBasePath) - 1] = 0;
00088             // Modify the key path.
00089             char *pos = (char *)ctx->keyPath.ptr + strlen((char *)ctx->keyPath.ptr) - strlen("ts");
00090             *pos = 'm';
00091             *(pos + 1) = 0;
00092             // Setup the manifest buffer
00093             ARM_UC_MM_SET_BUFFER(ctx->manifest, ctx->manifestBuffer);
00094             // Find the manifest
00095             err = ARM_UC_mmCfStoreFindKey(&ctx->keyPath);
00096             if (err.code != ERR_NONE) {
00097                 break;
00098             }
00099             event = ARM_UC_MM_EVENT_CF_BEGIN;
00100             ctx->state = ARM_UC_MM_INIT_FINDING;
00101             // no break;
00102         }
00103     case ARM_UC_MM_INIT_FINDING:
00104         if (event == UCMM_EVENT_CF_FIND_FAILED) {
00105             if (ctx->root) {
00106                 //TODO: assert! This should not be possible!
00107                 err.code = MFST_ERR_INVALID_STATE;
00108             } else {
00109                 // No more deps to find.
00110                 err.code = ERR_NONE;
00111             }
00112             break;
00113         }
00114         err = ARM_UC_mmCfStoreFindKeyFSM(event);
00115         if (err.code != ERR_NONE) {
00116             break;
00117         }
00118         // Read the manifest
00119         err = ARM_UC_mmCfStoreReadLastKey(&ctx->manifest);
00120         if (err.code != ERR_NONE) {
00121             break;
00122         }
00123         event = ARM_UC_MM_EVENT_CF_BEGIN;
00124         ctx->state = ARM_UC_MM_INIT_READING;
00125         // no break;
00126     case ARM_UC_MM_INIT_READING:
00127         // Read the manifest into a buffer
00128         err = ARM_UC_mmCfStoreReadLastKeyFSM(event);
00129         if (err.code != ERR_NONE) {
00130             break;
00131         }
00132         ctx->state = ARM_UC_MM_INIT_STATE_HASH_VERIFY;
00133         // Preserve the manifest key
00134         ARM_UC_mmCfStorePreserveLastKey();
00135 
00136         // no break;
00137     case ARM_UC_MM_INIT_STATE_HASH_VERIFY:
00138         // Verify the manifest hash
00139         err = ucmmValidateManifestHash(&ctx->manifest);
00140         if (err.code == ERR_NONE) {
00141             uint32_t val;
00142             err = ARM_UC_mmGetCryptoMode(&ctx->manifest, &val);
00143             if (err.code != ERR_NONE) {
00144                 break;
00145             }
00146             ucmm_crypto_flags_t cryptoMode = ARM_UC_mmGetCryptoFlags(val);
00147             if (cryptoMode.ecc || cryptoMode.rsa) {
00148                 ctx->state = ARM_UC_MM_INIT_STATE_PK_VERIFY;
00149             } else {
00150                 ctx->state = ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN;
00151             }
00152         }
00153         break;
00154     case ARM_UC_MM_INIT_STATE_PK_VERIFY:
00155         // Verify the manifest signature
00156         err = ucmmValidateSignature(&ctx->manifest);
00157         if (err.code == ERR_NONE) {
00158             ctx->state = ARM_UC_MM_INIT_STATE_PK_VERIFYING;
00159         }
00160         break;
00161     case ARM_UC_MM_INIT_STATE_PK_VERIFYING:
00162         err = ucmmValidateSignatureFSM(event);
00163         if (err.code == ERR_NONE) {
00164             ctx->state = ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN;
00165         }
00166         break;
00167     case ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN:
00168         // ATTACKVECTOR: If an attacker can add a manifest to the dependency prefix in the config store, the manifest
00169         // manager has no way to know that it is not valid, due to the flat file heirarchy.
00170         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_MANIFEST_BEGIN;
00171         // NO BREAK;
00172     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_MANIFEST_BEGIN:
00173         // Loop: manifest
00174         // Set the depidx to 0
00175         ctx->depidx = 0;
00176         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH;
00177         // NO BREAK;
00178     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH: {
00179             arm_uc_buffer_t dependency;
00180             arm_uc_buffer_t hash;
00181             // Read the dependency at depidx
00182             err = ARM_UC_mmGetManifestLinksElement(&ctx->manifest, ctx->depidx, &dependency);
00183             // If there isn't one
00184             if (err.code != ERR_NONE) {
00185                 break;
00186             }
00187             if (dependency.ptr == NULL) {
00188                 // Exit Loop: dependency
00189                 ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_END;
00190                 err.code = ERR_NONE;
00191                 break;
00192             }
00193             // Get the dependency hash
00194             err = ARM_UC_mmGetManifestLinksHash(&dependency, &hash);
00195             if (err.code != ERR_NONE) {
00196                 break;
00197             }
00198             // Store the dependency hash
00199             memcpy(ctx->currentHash, hash.ptr, min(hash.size, sizeof(ctx->currentHash)));
00200             // Format the dependency search key
00201             // The result of this operation is:
00202             // com.arm.mbed.update.mm.m.<root manifest hash>.deps.<dependency hash>.m
00203             // ASSUMES sizeof keypath > sizeof rootManifestBasePath
00204             strncpy((char *)ctx->keyPath.ptr, (char *)ctx->rootManifestBasePath, sizeof(ctx->keyPath.ptr));
00205             ctx->keyPath.size = strlen(ctx->keyPath.ptr);
00206             // Back up one space to remove the 'm'
00207             strncpy((char *)ctx->keyPath.ptr + ctx->keyPath.size - 1, "deps.", ctx->keyPath.size_max - ctx->keyPath.size);
00208             ctx->keyPath.size = strlen(ctx->keyPath.ptr);
00209             ARM_UC_Base64Enc(ctx->keyPath.ptr + ctx->keyPath.size, ctx->keyPath.size_max - ctx->keyPath.size, &hash);
00210             ctx->keyPath.size = strlen(ctx->keyPath.ptr);
00211             strncpy((char *)ctx->keyPath.ptr + ctx->keyPath.size, ".m", ctx->keyPath.size_max - ctx->keyPath.size);
00212             ctx->keyPath.size += 3; // add one for null terminator
00213 
00214             // Find the dependency in the config store
00215             err = ucmmCfstoreFindAndRead((char *)ctx->keyPath.ptr, &ctx->manifest);
00216             if (err.code == ERR_NONE) {
00217                 event = ARM_UC_MM_EVENT_BEGIN;
00218                 ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_READING_DEPENDENCY;
00219             }
00220             break;
00221         }
00222     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_READING_DEPENDENCY:
00223         // If there is no matching dependency
00224         if (event == UCMM_EVENT_CF_FIND_FAILED) {
00225             // Set the missing dep flag
00226             ctx->missingDep = 1;
00227             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK;
00228             // Continue...
00229             err.code = ERR_NONE;
00230             break;
00231         }
00232         // Find/Read the dependency manifest
00233         err = ucmmCfstoreFindAndReadFSM(event);
00234         if (err.code != ERR_NONE) {
00235             break;
00236         }
00237         // There is a matching dependency
00238         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_CHECK_HASH;
00239         // No break;
00240     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_CHECK_HASH: {
00241 #if MAX_HASH_BYTES != 256/8
00242 #error Hash size mismatch
00243 #endif
00244             uint8_t localhash[MAX_HASH_BYTES];
00245             arm_uc_buffer_t local = {
00246                 .size_max = MAX_HASH_BYTES,
00247                 .size     = 256 / 8,
00248                 .ptr      = localhash
00249             };
00250             arm_uc_buffer_t resource;
00251             const int32_t valueID = ARM_UC_MM_DER_RESOURCE;
00252             int rc = ARM_UC_mmDERGetSignedResourceValues(&resource, 1, &valueID, &resource);
00253             if (rc) {
00254                 err.code = MFST_ERR_DER_FORMAT;
00255                 break;
00256             }
00257             {
00258                 // Calculate the dependency hash
00259                 mbedtls_sha256_context ctx;
00260                 mbedtls_sha256_init(&ctx);
00261                 mbedtls_sha256_starts(&ctx, 0);
00262                 mbedtls_sha256_update(&ctx, resource.ptr, resource.size);
00263                 mbedtls_sha256_finish(&ctx, local.ptr);
00264             }
00265             {
00266                 arm_uc_buffer_t remote = {
00267                     .size_max = MAX_HASH_BYTES,
00268                     .size     = 256 / 8,
00269                     .ptr      = ctx->currentHash
00270                 };
00271                 // Validate the dependency hash
00272                 if (ARM_UC_BinCompareCT(&local, &remote)) {
00273                     // If invalid, Set the missing dep flag
00274                     ctx->missingDep = 1;
00275                     // Delete the manifest
00276                     ARM_UC_mmCfStoreDeleteLastKey();
00277                     ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_DELETE;
00278                     event = ARM_UC_MM_EVENT_CF_BEGIN;
00279                 } else {
00280                     // End Loop: dependency
00281                     ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ;
00282                     // Increment the depidx
00283                     ctx->depidx++;
00284                 }
00285             }
00286             break;
00287         }
00288     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_DELETE:
00289         err = ARM_UC_mmCfStoreDeleteLastKeyFSM(event);
00290         if (err.code == ERR_NONE) {
00291             // Make sure a URI exists.
00292             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK;
00293         }
00294         break;
00295     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK: {
00296             // modify the search path
00297             char *pos = (char *)ctx->keyPath.ptr + ctx->keyPath.size - 2; // null terminator
00298             strncpy(pos, "uri", ctx->keyPath.size_max - (ctx->keyPath.size - 2)); // null terminator
00299             // Check if there is a URI entry
00300             // HACK: No API for find without ovewriting the existing stored key. Use find/read even though we don't need the
00301             // data.
00302             err = ucmmCfstoreFindAndRead((char *)ctx->keyPath.ptr, &ctx->manifest);
00303             if (err.code != ERR_NONE) {
00304                 break;
00305             }
00306             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECKING;
00307             event = ARM_UC_MM_EVENT_CF_BEGIN;
00308             // no break
00309         }
00310     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECKING:
00311         if (event == UCMM_EVENT_CF_FIND_FAILED) {
00312             // TODO: Erase all deps and start over.
00313             err.code = MFST_ERR_INVALID_STATE;
00314             break;
00315         }
00316         err = ucmmCfstoreFindAndReadFSM(event);
00317         if (err.code == ERR_NONE) {
00318             // Increment the depidx
00319             ctx->depidx++;
00320             // End Loop: dependency
00321             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ;
00322         }
00323         break;
00324     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ:
00325         // Loop: dependency
00326         // Restore the manifest key
00327         ARM_UC_mmCfStoreRestoreLastKey();
00328         // Seek the current key
00329         err = ARM_UC_mmCfStoreSeekLastKey(0);
00330         if (err.code == ERR_NONE) {
00331             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_SEEKING;
00332         }
00333         break;
00334     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_SEEKING:
00335         err = ARM_UC_mmCfStoreSeekLastKeyFSM(event);
00336         if (err.code != ERR_NONE) {
00337             break;
00338         }
00339         // Read the current key
00340         err = ARM_UC_mmCfStoreReadLastKey(&ctx->manifest);
00341         if (err.code != ERR_NONE) {
00342             break;
00343         }
00344         ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READING;
00345         event = ARM_UC_MM_EVENT_CF_BEGIN;
00346         // no break
00347     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READING:
00348         err = ARM_UC_mmCfStoreReadLastKeyFSM(event);
00349         if (err.code == ERR_NONE) {
00350             ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH;
00351             // Preserve the manifest key
00352             ARM_UC_mmCfStorePreserveLastKey();
00353         }
00354         break;
00355     case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_END:
00356         // Format the dependency search key
00357         strncpy((char *)ctx->keyPath.ptr, (char *)ctx->rootManifestBasePath, sizeof(ctx->rootManifestBasePath));
00358         ctx->keyPath.size = sizeof(ctx->rootManifestBasePath) - 1;
00359         strncpy((char *)ctx->keyPath.ptr + ctx->keyPath.size, ".deps.*", ctx->keyPath.size_max - ctx->keyPath.size);
00360         ctx->keyPath.size += sizeof(".deps.*") - 1;
00361         // If the root flag is set
00362         if (ctx->root) {
00363             // Clear the root flag
00364             ctx->root = 0;
00365             // Start the dependency search
00366             err = ARM_UC_mmCfStoreFindKey(&ctx->keyPath);
00367         } else {
00368             // Continue the dependency search
00369             err = ARM_UC_mmCfStoreFindNextKey();
00370         }
00371         if (err.code == ERR_NONE) {
00372             event = ARM_UC_MM_EVENT_CF_BEGIN;
00373             // End Loop: manifest
00374             ctx->state = ARM_UC_MM_INIT_FINDING;
00375         }
00376         break;
00377     default:
00378         err.code = MFST_ERR_INVALID_STATE;
00379         break;
00380     }
00381     ARM_UC_MM_FSM_HELPER_FINISH(*ctx);
00382     if (err.code == ERR_NONE && ctx->missingDep == 1) {
00383         // TODO: Configure & trigger insert FSM
00384     }
00385     return err;
00386 }
00387 
00388 #endif // !MANIFEST_MANAGER_NO_STORAGE