Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

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