Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

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