Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 19:01:32 by 1.7.2