Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Mon Aug 29 2022 19:53:38 by
