bug fix

Dependencies:   HTS221

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_mmInsertManifest.c Source File

arm_uc_mmInsertManifest.c

Go to the documentation of this file.
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_mmCryptoUtils.h"
00020 #include "arm_uc_mmCommon.h"
00021 #include "arm_uc_mmConfig.h"
00022 #include "arm_uc_mmStateSelector.h"
00023 #include "arm_uc_mmDerManifestAccessors.h"
00024 #include "arm_uc_mmDerManifestParser.h"
00025 #include "arm_uc_mmGetLatestTimestamp.h"
00026 #include "arm_uc_mmFSMHelper.h"
00027 #include "arm_uc_mmInsertManifest.h"
00028 #include "update-client-common/arm_uc_scheduler.h"
00029 
00030 #include "update-client-manifest-manager/update-client-manifest-manager-context.h"
00031 #include "update-client-manifest-manager/update-client-manifest-manager.h"
00032 #include "update-client-manifest-manager/update-client-manifest-types.h"
00033 
00034 #include "pal4life-device-identity/pal_device_identity.h"
00035 #include "pal.h"
00036 
00037 #include <stdint.h>
00038 #include <stdio.h>
00039 #include <stddef.h>
00040 #include <string.h>
00041 
00042 /**
00043  * @file arm_uc_mmInsertManifest.c
00044  * @brief Inserts a manifest into a slot specified by the manifest.
00045  * @details This API is used by the manifest manager to validate and store a manifest.
00046  *
00047  * The workflow for inserting a manifest is:
00048  * 1. Check the version of the manifest
00049  * 2. Validate the cryptographic mode
00050  * 3. Verify the hash of the manifest.
00051  * 4. Verify each signature of the manifest.
00052  * 5. Validate the applicability of the manifest (GUID matching)
00053  * 6. Validate the storage identifier
00054  * TBD: Store the manifest in the KCM
00055  *
00056  * NOTE: There is a security vs. energy tradeoff in this code.
00057  * To optimize for energy, the cheapest fields should be checked first, that means checking applicability before
00058  * hash or signature. However, to optimize for security, we must prioritize safety over energy. Since parsers are
00059  * notorious sources of bugs, we must make every effort to protect the parser from insecure content. This means
00060  * accessing the absolute minimum of fields prior to verifyinng the signature.
00061  *
00062  * The current version of this code optimizes for security. Once the parser has been more thoroughly validated, we can
00063  * consider exposing it to more unvalidated data as an energy saving measure.
00064  *
00065  * @dot
00066  * digraph {
00067  *     Idle
00068  *     Idle -> Begin [label="[event == BEGIN]"]
00069  *     Begin
00070  *     Begin -> VerifyBasicParameters
00071  *     VerifyBasicParameters
00072  *     // Validate the manifest size             (This is a precursor to security validation)
00073  *     // Validate the manifest version          (This is required in order to know how to parse the manifest)
00074  *     // Validate the manifest encryption mode  (This is required in order to know how to validate the signature)
00075  *     VerifyBasicParameters -> VerifyHash
00076  *     VerifyBasicParameters -> VerifyFail [label="[Basic Parameters invalid]"]
00077  *     VerifyHash
00078  *     VerifyHash -> VerifySignatureLoopStart
00079  *     VerifyHash -> VerifyFail [label="[Hash invalid]"]
00080  *     VerifySignatureLoopStart
00081  *     VerifySignatureLoopStart -> VerifySignatureStart
00082  *     VerifySignatureStart
00083  *     VerifySignatureStart -> VerifySignature
00084  *     VerifySignatureStart -> VerifyParameters [label="[No More Signatures]"]
00085  *     VerifySignature
00086  *     VerifySignature -> VerifyParameters [label="[Last Signature]"]
00087  *     VerifySignature -> VerifyFail [label="[Signature invalid]"]
00088  *     // Validate the applicability of the manifest (GUID matching)
00089  *     // Validate the storage identifier
00090  *     VerifyParameters
00091  *     VerifyParameters -> VerifyTimestamp
00092  *     VerifyParameters -> VerifyFail [label="[Parameters invalid]"]
00093  *     VerifyTimestampStart
00094  *     VerifyTimestampStart -> VerifyTimestamp
00095  *     VerifyTimestamp
00096  *     VerifyTimestamp -> VerifyApplication
00097  *     VerifyTimestamp -> VerifyFail [label="[Timestamp too old]"]
00098  *     VerifyApplication
00099  *     VerifyApplication -> VerifyDone
00100  *     VerifyApplication -> VerifyFail [label="[App denied]"]
00101  *     VerifyFail
00102  *     VerifyFail -> Idle
00103  *     VerifyDone
00104  *     VerifyDone -> AlertHub
00105  *     AlertHub
00106  *     AlertHub -> Idle
00107  * }
00108  * @enddot
00109  */
00110 
00111 #if ARM_UC_MANIFEST_MANAGER_TRACE_ENABLE
00112 static const char* ARM_UC_mmInsertState2Str(uint32_t state)
00113 {
00114     switch (state) {
00115         #define ENUM_AUTO(name) case name: return #name;
00116         #define ENUM_FIXED(name, val) ENUM_AUTO(name)
00117         ARM_UC_MM_INS_STATE_LIST
00118         #undef ENUM_AUTO
00119         #undef ENUM_FIXED
00120     default:
00121         return "Unknown State";
00122     }
00123 }
00124 #endif
00125 
00126 #define max(A,B) ((A)>(B)?(A):(B))
00127 
00128 /** @brief Validate that the resource contained in this signed container is a manifest.
00129  */
00130 static arm_uc_error_t validateResourceType(arm_uc_buffer_t* buffer)
00131 {
00132     arm_uc_error_t err = {MFST_ERR_NONE};
00133     arm_uc_buffer_t type = { 0 };
00134     // Read the resource type field.
00135     err = ARM_UC_mmDERSignedResourceGetSingleValue(buffer,
00136                                                    ARM_UC_MM_DER_RESOURCE_TYPE, &type);
00137     if (type.ptr == NULL)
00138     {
00139         err.code = MFST_ERR_DER_FORMAT;
00140     }
00141     else if (err.error == ERR_NONE)
00142     {
00143         // The resource type must be a manifest.
00144         if (ARM_UC_mmDerBuf2Uint(&type) != 0)
00145         {
00146             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_DER_FORMAT);
00147         }
00148     }
00149     return err;
00150 }
00151 /** @brief Validate that this manifest is a supported version
00152  */
00153 static arm_uc_error_t validateManifestVersion(arm_uc_buffer_t* buffer)
00154 {
00155     uint32_t val = 0;
00156     // Read the manifest version
00157     arm_uc_error_t err = ARM_UC_mmGetVersion(buffer, &val);
00158     if (err.code == MFST_ERR_NONE)
00159     {
00160         // Verify the manifest version
00161         if (val != MANIFEST_SUPPORTED_VERSION) {
00162             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_VERSION);
00163         }
00164     }
00165     return err;
00166 }
00167 
00168 /** @brief Validate the manifest size
00169  */
00170 static arm_uc_error_t validateManifestSize(arm_uc_buffer_t* buffer)
00171 {
00172     arm_uc_error_t err = {MFST_ERR_NONE};
00173     arm_uc_buffer_t val = {0};
00174 
00175     // Get the manifest inner part
00176     err = ARM_UC_mmDERSignedResourceGetSingleValue(buffer, ARM_UC_MM_DER_MFST, &val);
00177     if (err.error == ERR_NONE)
00178     {
00179         // Make sure that the manifest does not overrun.
00180         uintptr_t bufend = (uintptr_t)buffer->ptr + buffer->size;
00181         uintptr_t valend = (uintptr_t)val.ptr + val.size;
00182         if (bufend < valend)
00183         {
00184             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_SIZE);
00185         }
00186         // TODO: There should be a minimum size for the manifest too.
00187     }
00188     return err;
00189 }
00190 
00191 /** @brief Validate the crypto mode
00192  *  @details The manifest must contain a cryptographic mode identifier. Only a small number of modes are supported. If
00193  *           the manifest is to be processed, then one of these modes must be supported.
00194  *
00195  *           While the manifest format supports OID cryptographic mode identifiers, these are not currently supported in
00196  *           the update client.
00197  */
00198 static arm_uc_error_t validateCryptoMode(arm_uc_buffer_t* buffer, arm_uc_mm_crypto_flags_t* flags)
00199 {
00200     uint32_t cryptoMode = 1U; // default SHA256 and ECC
00201     arm_uc_error_t err = ARM_UC_mmGetCryptoMode(buffer, &cryptoMode);
00202     if (err.error == ERR_NONE)
00203     {
00204         if (cryptoMode <= MFST_CRYPT_UNINIT || MFST_CRYPT_MAX <= cryptoMode)
00205         {
00206             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_CRYPTO_MODE);
00207         }
00208         else
00209         {
00210             *flags = ARM_UC_mmGetCryptoFlags(cryptoMode);
00211         }
00212     }
00213     return err;
00214 }
00215 
00216 // Validate that the manifest applies to this device
00217 static arm_uc_error_t validateFirmwareApplicability(arm_uc_buffer_t* buffer)
00218 {
00219     arm_uc_buffer_t vendor_guid = {0};
00220     arm_uc_buffer_t class_guid  = {0};
00221     arm_uc_buffer_t device_guid = {0};
00222 
00223     arm_uc_error_t err = {MFST_ERR_NONE};
00224     if (err.code == MFST_ERR_NONE)
00225         err = ARM_UC_mmGetVendorGuid(buffer, &vendor_guid);
00226     if (err.code == MFST_ERR_NONE)
00227         err = ARM_UC_mmGetClassGuid(buffer, &class_guid);
00228     if (err.code == MFST_ERR_NONE)
00229         err = ARM_UC_mmGetDeviceGuid(buffer, &device_guid);
00230     if (err.code == MFST_ERR_NONE)
00231         err = pal_deviceIdentityCheck(
00232             (vendor_guid.size != 0UL ? &vendor_guid : NULL),
00233             (class_guid.size != 0UL ? &class_guid : NULL),
00234             (device_guid.size != 0UL ? &device_guid : NULL)
00235         );
00236     return err;
00237 }
00238 /*
00239  * DOT Setup
00240  * DOT: digraph {
00241  */
00242 
00243 /* @brief Idle state
00244  * @details The idle state generates no events and causes no state transitions. It only moves to a new state when the
00245  *          `ARM_UC_MM_EVENT_BEGIN` event is received.
00246  * DOT States:
00247  * DOT:    Idle
00248  * DOT:    Idle -> Begin [label="[event == BEGIN]"]
00249  */
00250 static arm_uc_error_t state_idle(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00251 {
00252     arm_uc_error_t err = {MFST_ERR_NONE};
00253     if (*event == ARM_UC_MM_EVENT_BEGIN)
00254     {
00255         ctx->state = ARM_UC_MM_INS_STATE_BEGIN;
00256     }
00257     return err;
00258 }
00259 /* @brief Begin state
00260  * @details This is an empty placeholder state that is used as a state transition target for Idle. This allows
00261  *          modifications to the FSM flow without modifying Idle.
00262  * DOT States:
00263  * DOT:    Begin
00264  * DOT:    Begin -> VerifyBasicParameters
00265  */
00266 static arm_uc_error_t state_begin(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00267 {
00268     arm_uc_error_t err = {MFST_ERR_NONE};
00269     ctx->state = ARM_UC_MM_INS_STATE_VERIFY_BASIC_PARAMS;
00270     return err;
00271 }
00272 /* @brief Verify critical pre-security parameters
00273  * @details Some parameters must be verified before security validation. These parameters are critical to either finding
00274  *          or validating the security parameters themselves. The parameters validated are:
00275  *
00276  * * The resource size             (This is a precursor to security validation)
00277  * * The resource is a manifest    (A non-manifest will not be accepted)
00278  * * The manifest version          (This is required in order to know how to parse the manifest)
00279  * * The manifest encryption mode  (This is required in order to know how to validate the signature)
00280  *
00281  * DOT States:
00282  * DOT:    VerifyBasicParameters
00283  * DOT:    VerifyBasicParameters -> VerifyHash
00284  * DOT:    VerifyBasicParameters -> VerifyFail [label="[Basic Parameters invalid]"]
00285  */
00286 static arm_uc_error_t state_verifyBasicParameters(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00287 {
00288     arm_uc_error_t err = {MFST_ERR_NONE};
00289 
00290     if (err.error == ERR_NONE)
00291     {
00292         err = validateResourceType(&ctx->manifest);
00293     }
00294     if (err.error == ERR_NONE)
00295     {
00296         err = validateManifestSize(&ctx->manifest);
00297     }
00298     if (err.error == ERR_NONE)
00299     {
00300         err = validateManifestVersion(&ctx->manifest);
00301     }
00302     if (err.error == ERR_NONE)
00303     {
00304         err = validateCryptoMode(&ctx->manifest, &ctx->cryptoMode);
00305     }
00306     // Set the state based on error condition
00307     if (err.error == ERR_NONE)
00308     {
00309         ctx->state = ARM_UC_MM_INS_STATE_HASH_VERIFY;
00310     }
00311     else
00312     {
00313         ctx->state = ARM_UC_MM_INS_STATE_VERIFY_FAIL;
00314     }
00315     return err;
00316 }
00317 /** @brief   Verify the manifest hash
00318  *  @details Manifest hash verification happens in a single state. This is because hash verification is currently
00319  *           considered to be a blocking operation. If an asynchronous hash accelerator is used, this will need to be
00320  *           modified to use two states to handle hash initiation and waiting for completion.
00321  *
00322  * DOT States:
00323  * DOT:     VerifyHash
00324  * DOT:     VerifyHash -> VerifySignatureLoopStart
00325  * DOT:     VerifyHash -> VerifyFail [label="[Hash invalid]"]
00326  */
00327 static arm_uc_error_t state_verifyHash(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00328 {
00329     arm_uc_error_t err = ARM_UC_mmValidateManifestHash(&ctx->manifest);
00330     if (err.error == ERR_NONE)
00331     {
00332         // If the cryptoMode specifies either ecc or rsa, then we can validate that.
00333         if(ctx->cryptoMode.ecc || ctx->cryptoMode.rsa)
00334         {
00335             ctx->state = ARM_UC_MM_INS_STATE_VERIFY_SIG_LOOP;
00336         }
00337         else
00338         {
00339             // Unsigned manifests are not supported at this time, so they count as a failure.
00340             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_INVALID_SIGNATURE);
00341             ctx->state = ARM_UC_MM_INS_STATE_VERIFY_FAIL;
00342         }
00343     }
00344     else
00345     {
00346         ARM_UC_MFST_SET_ERROR(err, MFST_ERR_HASH);
00347         ctx->state = ARM_UC_MM_INS_STATE_VERIFY_FAIL;
00348     }
00349     return err;
00350 }
00351 /** @brief Start the signature verification loop.
00352  *  @details This state provides initialization for the signature verification loop.
00353  *           The outer loop is tracked by `loopCounters[0]` and represents the signature index.
00354  *
00355  * DOT States:
00356  * DOT:     VerifySignatureLoopStart
00357  * DOT:     VerifySignatureLoopStart -> VerifySignatureStart
00358  */
00359 static arm_uc_error_t state_verifySignatureLoopStart(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00360 {
00361     arm_uc_error_t err = {MFST_ERR_NONE};
00362     // Set the exterior loop counter
00363     ctx->loopCounters[0] = 0;
00364     ctx->state = ARM_UC_MM_INS_STATE_VERIFY_SIG_START;
00365     return err;
00366 }
00367 /** @brief   Begin verifying the signature.
00368  *  @details This calls the ARM_UC_mmValidateSignature setup function, but does not start the signature verification
00369  *           state machine. `ARM_UC_mmValidateSignature` attempts to read a signature at the index specified by the
00370  *           outer loop counter (`loopCounters[0]`). If it fails, it assumes that all signatures have been processed.
00371  *           If at least one signature has been processed, then continue with validation, but a minimum of one signature
00372  *           is required for validation.
00373  *
00374  * DOT States:
00375  * DOT:     VerifySignatureStart
00376  * DOT:     VerifySignatureStart -> VerifySignature
00377  * DOT:     VerifySignatureStart -> VerifyParameters [label="[No More Signatures]"]
00378  */
00379 static arm_uc_error_t state_verifySignatureStart(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00380 {
00381     // start the signature verification
00382     arm_uc_error_t err = ARM_UC_mmValidateSignature(&ctx->signatureContext,
00383                                                     ARM_UC_mmCallbackFSMEntry,
00384                                                     &ctx->manifest,
00385                                                     &ctx->certificateStorage,
00386                                                     ctx->loopCounters[0]);
00387     if (err.error == ERR_NONE)
00388     {
00389         ctx->state = ARM_UC_MM_INS_STATE_VERIFY_SIG_WAIT;
00390         *event = ARM_UC_MM_RC_NONE;
00391         ARM_UC_MFST_SET_ERROR(err, MFST_ERR_PENDING);
00392     }
00393     // If there are no more signatures and at least one signature was validated
00394     if (err.code == ARM_UC_DP_ERR_NO_MORE_ELEMENTS)
00395     {
00396         if (ctx->loopCounters[0] >= 1)
00397         {
00398             // Signature validation done. Move on to parameter validation.
00399             ctx->state = ARM_UC_MM_INS_STATE_VERIFY_PARAMS;
00400             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_NONE);
00401         }
00402         else
00403         {
00404             // WARNING: If the fingerprint is empty, MFST_ERR_INVALID_SIGNATURE is returned.
00405             // At least one signature is required.
00406             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_INVALID_SIGNATURE);
00407             ctx->state = ARM_UC_MM_INS_STATE_VERIFY_FAIL;
00408         }
00409     }
00410     return err;
00411 }
00412 /** @brief   Wait for signature validation to complete.
00413  *  @details Calls the `ARM_UC_mmValidateSignature` state machine and collects exit status. When signature validation is
00414  *           complete, the return value will be `MFST_ERR_NONE`.
00415  *
00416  * DOT States:
00417  * DOT:     VerifySignature
00418  * DOT:     VerifySignature -> VerifyFail [label="[Signature invalid]"]
00419  * DOT:     VerifySignature -> VerifySignatureStart
00420  */
00421 static arm_uc_error_t state_verifySignature(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00422 {
00423     arm_uc_error_t err = {MFST_ERR_NONE};
00424     // Wait for the signature verification to end.
00425     // If the signature validation ended
00426     if (*event == ARM_UC_MM_RC_DONE)
00427     {
00428         // Increment the loop counter
00429         ctx->loopCounters[0] += 1;
00430         // Return to the beginning of the loop.
00431         ctx->state = ARM_UC_MM_INS_STATE_VERIFY_SIG_START;
00432     }
00433     else if (*event == ARM_UC_MM_RC_ERROR)
00434     {
00435         err = ctx->signatureContext.storedError;
00436     }
00437     else
00438     {
00439         ARM_UC_MFST_SET_ERROR(err,  MFST_ERR_BAD_EVENT);
00440     }
00441     return err;
00442 }
00443 /** @brief   Validates remaining parsable parameters
00444  *  @details This currently means only the firmware applicability, as identified by UUID. Several additiional parameters
00445  *           could be validated:
00446  *
00447  *           * Storage identifier
00448  *           * Payload type identifier
00449  *           * URI validation in payload reference
00450  *           * Valid size of payload hash
00451  *           * nonce size, non-zero
00452  *           * Valid From, Valid To
00453  *           * timestamp
00454  *           * Encryption info
00455  *
00456  *
00457  * DOT States:
00458  * DOT:     VerifyParameters
00459  * DOT:     VerifyParameters -> VerifyApplication
00460  * DOT:     VerifyParameters -> VerifyFail [label="[Parameters invalid]"]
00461  */
00462 static arm_uc_error_t state_verifyParameters(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00463 {
00464     arm_uc_error_t err = validateFirmwareApplicability(&ctx->manifest);
00465     if (err.error == ERR_NONE)
00466     {
00467         ctx->state = ARM_UC_MM_INS_STATE_VERIFY_TS_START;
00468     }
00469     return err;
00470 }
00471 /** @brief   Initiate timestamp verification.
00472  *  @details This starts the process of loading the active timestamp. This may be a non-blocking operation.
00473  *
00474  * DOT States:
00475  * DOT:     VerifyTimestampStart
00476  * DOT:     VerifyTimestampStart -> VerifyTimestamp
00477  */
00478 static arm_uc_error_t state_verifyTimestampStart(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00479 {
00480     // Since this is a root manifest, extract maximum stored timestamp
00481     arm_uc_error_t err = getLatestManifestTimestamp(&ctx->max_ts, NULL);
00482     if (err.error == ERR_NONE)
00483     {
00484         ctx->state = ARM_UC_MM_INS_STATE_VERIFY_TS;
00485         *event = ARM_UC_MM_EVENT_BEGIN;
00486     }
00487     return err;
00488 }
00489 /** @brief   Waits for the active timestamp to be loaded.
00490  *  @details Once the active timestamp has been loaded, this validates the inserted manifest timestamp.
00491  *
00492  * DOT States:
00493  * DOT:    VerifyTimestamp
00494  * DOT:    VerifyTimestamp -> VerifyApplication
00495  * DOT:    VerifyTimestamp -> VerifyFail [label="[Timestamp too old]"]
00496  */
00497 static arm_uc_error_t state_verifyTimestamp(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00498 {
00499     arm_uc_error_t err = getLatestManifestTimestampFSM(*event);
00500     if (err.error == ERR_NONE)
00501     {
00502         err = ARM_UC_mmGetTimestamp(&ctx->manifest, &ctx->current_ts);
00503     }
00504     if (err.error == ERR_NONE)
00505     {
00506 #if MANIFEST_ROLLBACK_PROTECTION
00507         // Validate the timestamp for rollback protection.
00508         if (arm_uc_mmContext.max_ts >= arm_uc_mmContext.current_ts)
00509         {
00510             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_ROLLBACK);
00511         }
00512         else
00513 #endif
00514         {
00515             ARM_UC_MFST_SET_ERROR(err, MFST_ERR_NONE);
00516             ctx->state = ARM_UC_MM_INS_STATE_VERIFY_APP;
00517         }
00518     }
00519     return err;
00520 }
00521 
00522 /** @brief   Calls out to a handler provided by the application.
00523  *  @details Currently unimplemented.
00524  *
00525  * DOT States:
00526  * DOT:     VerifyApplication
00527  * DOT:     VerifyApplication -> VerifyDone
00528  * DOT:     VerifyApplication -> VerifyFail [label="[App denied]"]
00529  */
00530 static arm_uc_error_t state_verifyApplication(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00531 {
00532     arm_uc_error_t err = {MFST_ERR_NONE};
00533     if (err.error == ERR_NONE)
00534     {
00535         ctx->state = ARM_UC_MM_INS_STATE_VERIFY_DONE;
00536     }
00537     return err;
00538 }
00539 /** @brief   Verification has failed.
00540  *  @details This state will never be entered. This is for documentation purposes only. The state machine exits when an
00541  *           error is detected, so this state cannot be entered. The hub will be notified via the state machine's error
00542  *           handler.
00543  *
00544  * DOT States:
00545  * DOT:     VerifyFail
00546  * DOT:     VerifyFail -> Idle
00547  */
00548 
00549 
00550 /** @brief   Verification has completed successfully.
00551  *  @details This is a placeholder state that may be useful if more operations must be performed after verification,
00552  *           for example, storage of the manifest.
00553  *
00554  * DOT States:
00555  * DOT:     VerifyDone
00556  * DOT:     VerifyDone -> AlertHub
00557  */
00558 static arm_uc_error_t state_verifyDone(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00559 {
00560     arm_uc_error_t err = {MFST_ERR_NONE};
00561     if (err.error == ERR_NONE)
00562     {
00563         ctx->state = ARM_UC_MM_INS_STATE_ALERT;
00564     }
00565     return err;
00566 }
00567 /** @brief   Alert the hub that insert has finished processing the manifest.
00568  *  @details Queues a callback to the hub, that reports completion.
00569  *
00570  * DOT States:
00571  * DOT:     AlertHub
00572  * DOT:     AlertHub -> Idle
00573  */
00574 static arm_uc_error_t state_alertHub(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event)
00575 {
00576     arm_uc_error_t err = {MFST_ERR_NONE};
00577     return err;
00578 }
00579 /**
00580  * DOT Teardown
00581  * DOT: }
00582  */
00583 
00584 arm_uc_error_t ARM_UC_mmInsertFSM(uint32_t event)
00585 {
00586     arm_uc_error_t err = {MFST_ERR_NONE};
00587     struct arm_uc_mmInsertContext_t* ctx;
00588     if (arm_uc_mmPersistentContext.ctx == NULL || *arm_uc_mmPersistentContext.ctx == NULL)
00589     {
00590         return (arm_uc_error_t){MFST_ERR_NULL_PTR};
00591     }
00592     ctx = &(*arm_uc_mmPersistentContext.ctx)->insert;
00593 
00594     uint32_t oldState;
00595 #if ARM_UC_MM_ENABLE_INSERT_TEST_VECTORS
00596     uint32_t oldEvent;
00597 #endif
00598     ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "> %s (%u)\n", __PRETTY_FUNCTION__, (unsigned)event);
00599     do {
00600         // Preserve the old state to check for state transitions
00601         oldState = ctx->state;
00602 
00603 #if ARM_UC_MM_ENABLE_INSERT_TEST_VECTORS
00604         // Preserve the old event for testing
00605         oldEvent = event;
00606 #endif
00607         // Reset error logging
00608         arm_uc_mmPersistentContext.errorFile = NULL;
00609         arm_uc_mmPersistentContext.errorLine = 0;
00610 
00611         ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "+ %s state: %s(%u)\n", __PRETTY_FUNCTION__,
00612             ARM_UC_mmInsertState2Str(ctx->state), (unsigned)ctx->state);\
00613         switch (ctx->state)
00614         {
00615             case ARM_UC_MM_INS_STATE_IDLE:
00616                 err = state_idle(ctx, &event);
00617                 break;
00618             case ARM_UC_MM_INS_STATE_BEGIN:
00619                 err = state_begin(ctx, &event);
00620                 break;
00621             case ARM_UC_MM_INS_STATE_VERIFY_BASIC_PARAMS:
00622                 err = state_verifyBasicParameters(ctx, &event);
00623                 break;
00624             case ARM_UC_MM_INS_STATE_HASH_VERIFY:
00625                 err = state_verifyHash(ctx, &event);
00626                 break;
00627             case ARM_UC_MM_INS_STATE_VERIFY_SIG_LOOP:
00628                 err = state_verifySignatureLoopStart(ctx, &event);
00629                 break;
00630             case ARM_UC_MM_INS_STATE_VERIFY_SIG_START:
00631                 err =  state_verifySignatureStart(ctx, &event);
00632                 break;
00633             case ARM_UC_MM_INS_STATE_VERIFY_SIG_WAIT:
00634                 err = state_verifySignature(ctx, &event);
00635                 break;
00636             case ARM_UC_MM_INS_STATE_VERIFY_PARAMS:
00637                 err = state_verifyParameters(ctx, &event);
00638                 break;
00639             case ARM_UC_MM_INS_STATE_VERIFY_TS_START:
00640                 err = state_verifyTimestampStart(ctx, &event);
00641                 break;
00642             case ARM_UC_MM_INS_STATE_VERIFY_TS:
00643                 err = state_verifyTimestamp(ctx, &event);
00644                 break;
00645             case ARM_UC_MM_INS_STATE_VERIFY_APP:
00646                 err = state_verifyApplication(ctx, &event);
00647                 break;
00648             case ARM_UC_MM_INS_STATE_VERIFY_DONE:
00649                 err = state_verifyDone(ctx, &event);
00650                 break;
00651             case ARM_UC_MM_INS_STATE_ALERT:
00652                 err = state_alertHub(ctx, &event);
00653                 break;
00654             case ARM_UC_MM_INS_STATE_INVALID:
00655             default:
00656                 err = (arm_uc_error_t){MFST_ERR_INVALID_STATE};
00657                 break;
00658         }
00659 #if ARM_UC_MM_ENABLE_INSERT_TEST_VECTORS
00660         if (arm_uc_mmPersistentContext.testHook)
00661         {
00662             arm_uc_mmPersistentContext.testHook("insert", *arm_uc_mmPersistentContext.ctx, oldState, oldEvent, err);
00663         }
00664 #endif
00665     } while (err.code == MFST_ERR_NONE && oldState != ctx->state);
00666     ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "< %s %c%c:%hu (%s)\n", __PRETTY_FUNCTION__, err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err));
00667     return err;
00668 }