Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_firmware_manager.c Source File

arm_uc_firmware_manager.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 "update-client-firmware-manager/arm_uc_firmware_manager.h"
00020 #include "update-client-common/arm_uc_common.h"
00021 
00022 #include "update-client-paal/arm_uc_paal_update.h"
00023 
00024 #include <stdio.h>
00025 #include <stdbool.h>
00026 
00027 static ARM_UCFM_SignalEvent_t ucfm_handler = NULL;
00028 
00029 static ARM_UCFM_Setup_t* package_configuration = NULL;
00030 static uint32_t package_offset = 0;
00031 static bool ready_to_receive = false;
00032 
00033 static arm_uc_callback_t arm_uc_event_handler_callback = { 0 };
00034 
00035 static arm_uc_mdHandle_t mdHandle = { 0 };
00036 static arm_uc_cipherHandle_t cipherHandle = { 0 };
00037 static arm_uc_buffer_t* front_buffer = NULL;
00038 static arm_uc_buffer_t* back_buffer = NULL;
00039 
00040 #define UCFM_DEBUG_OUTPUT 0
00041 
00042 
00043 static void arm_uc_signal_ucfm_handler(uint32_t event);
00044 
00045 /******************************************************************************/
00046 /* Debug output functions for writing formatted output                        */
00047 /******************************************************************************/
00048 
00049 #if UCFM_DEBUG_OUTPUT
00050 
00051 static void debug_output_decryption(const uint8_t* encrypted,
00052                                     arm_uc_buffer_t* decrypted)
00053 {
00054     for (size_t index = 0; index < UCFM_MAX_BLOCK_SIZE; index++)
00055     {
00056         if (index < decrypted->size)
00057         {
00058             uint8_t symbol = encrypted[index];
00059 
00060             printf("%02X", symbol);
00061         }
00062         else
00063         {
00064             printf("  ");
00065         }
00066     }
00067 
00068     printf("\t:\t");
00069 
00070     for (size_t index = 0; index < UCFM_MAX_BLOCK_SIZE; index++)
00071     {
00072         if (index < decrypted->size)
00073         {
00074             uint8_t symbol = encrypted[index];
00075 
00076             if ((symbol > 32) && (symbol < 127))
00077             {
00078                 printf("%c", symbol);
00079             }
00080             else
00081             {
00082                 printf(" ");
00083             }
00084         }
00085         else
00086         {
00087             printf(" ");
00088         }
00089     }
00090 
00091     printf("\t:\t");
00092 
00093     for (size_t index = 0; index < decrypted->size_max; index++)
00094     {
00095         if (index < decrypted->size)
00096         {
00097             uint8_t symbol = decrypted->ptr[index];
00098 
00099             if ((symbol > 32) && (symbol < 127))
00100             {
00101                 printf("%c", symbol);
00102             }
00103             else
00104             {
00105                 printf(" ");
00106             }
00107         }
00108         else
00109         {
00110             printf(" ");
00111         }
00112     }
00113 
00114     printf("\r\n");
00115 }
00116 
00117 static void debug_output_validation(arm_uc_buffer_t* hash,
00118                                     arm_uc_buffer_t* output_buffer)
00119 {
00120     printf("\r\n");
00121     printf("expected hash  : ");
00122     for (size_t index = 0; index < hash->size; index++)
00123     {
00124         printf("%02X", hash->ptr[index]);
00125     }
00126     printf("\r\n");
00127 
00128     printf("calculated hash: ");
00129     for (size_t index = 0; index < output_buffer->size; index++)
00130     {
00131         printf("%02X", output_buffer->ptr[index]);
00132     }
00133     printf("\r\n");
00134     printf("\r\n");
00135 }
00136 
00137 #endif
00138 
00139 /******************************************************************************/
00140 
00141 /* Hash calculation is performed using the output buffer. This function fills
00142    the output buffer with data from the PAL.
00143 */
00144 static void arm_uc_internal_process_hash(void)
00145 {
00146     bool double_buffering = (front_buffer != back_buffer);
00147     bool needs_more_data = (package_offset < package_configuration->package_size);
00148     arm_uc_error_t status = { .code = ERR_NONE };
00149     uint32_t error_event = UCFM_EVENT_FINALIZE_ERROR;
00150 
00151     if (double_buffering && needs_more_data)
00152     {
00153 #if UCFM_DEBUG_OUTPUT
00154         printf("double buffering: %p %" PRIX32 "\r\n", back_buffer, back_buffer->size_max);
00155 #endif
00156 
00157         /* if using double buffering, initiate a new data read as soon as possible */
00158         /* Indicate read size */
00159         uint32_t bytes_remaining = package_configuration->package_size - package_offset;
00160         back_buffer->size = (bytes_remaining > back_buffer->size_max)?
00161                                 back_buffer->size_max : bytes_remaining;
00162 
00163         /* initiate read from PAL */
00164         status = ARM_UCP_Read(package_configuration->package_id,
00165                               package_offset,
00166                               back_buffer);
00167     }
00168 
00169     if (status.error == ERR_NONE)
00170     {
00171         /* process data in front buffer */
00172         ARM_UC_cryptoHashUpdate(&mdHandle, front_buffer);
00173 
00174         if (needs_more_data)
00175         {
00176             /* if we're actually using two buffers, the read operation was initiated earlier,
00177              * otherwise it needs to be initiated now, after we're done hashing the only
00178              * buffer that we're using
00179              */
00180             if (!double_buffering)
00181             {
00182 #if UCFM_DEBUG_OUTPUT
00183                 printf("single buffering: %p\r\n", front_buffer);
00184 #endif
00185                 /* Indicate read size */
00186                 uint32_t bytes_remaining = package_configuration->package_size - package_offset;
00187                 back_buffer->size = (bytes_remaining > back_buffer->size_max)?
00188                                         back_buffer->size_max : bytes_remaining;
00189 
00190                 /* initiate read from PAL */
00191                 status = ARM_UCP_Read(package_configuration->package_id,
00192                                       package_offset,
00193                                       back_buffer);
00194             }
00195         }
00196         else
00197         {
00198             /* invert status code so that it has to be set explicitly for success */
00199             status.code = ERR_INVALID_PARAMETER;
00200 
00201             /* finalize hash calculation */
00202             uint8_t hash_output_ptr[2 * UCFM_MAX_BLOCK_SIZE];
00203             arm_uc_buffer_t hash_buffer = {
00204                 .size_max = sizeof(hash_output_ptr),
00205                 .size = 0,
00206                 .ptr = hash_output_ptr
00207             };
00208 
00209             ARM_UC_cryptoHashFinish(&mdHandle, &hash_buffer);
00210 
00211             /* size check before memcmp call */
00212             if (hash_buffer.size == package_configuration->hash->size)
00213             {
00214                 int diff = memcmp(hash_buffer.ptr,
00215                                   package_configuration->hash->ptr,
00216                                   package_configuration->hash->size);
00217 
00218 #if UCFM_DEBUG_OUTPUT
00219                 debug_output_validation(package_configuration->hash,
00220                                         &hash_buffer);
00221 #endif
00222 
00223                 /* hash matches */
00224                 if (diff == 0)
00225                 {
00226                     UC_FIRM_TRACE("UCFM_EVENT_FINALIZE_DONE");
00227 
00228                     arm_uc_signal_ucfm_handler(UCFM_EVENT_FINALIZE_DONE);
00229                     status.code = ERR_NONE;
00230                 }
00231                 else
00232                 {
00233                     /* use specific event for "invalid hash" */
00234                     UC_FIRM_ERR_MSG("Invalid image hash");
00235 
00236                     error_event = UCFM_EVENT_FINALIZE_INVALID_HASH_ERROR;
00237                 }
00238             }
00239         }
00240 
00241         /* Front buffer is processed, back buffer might be reading more data.
00242            Swap buffer so that data will be ready in front buffer
00243         */
00244         arm_uc_buffer_t* temp = front_buffer;
00245         front_buffer = back_buffer;
00246         back_buffer = temp;
00247     }
00248 
00249     /* signal error if status is not clean */
00250     if (status.error != ERR_NONE)
00251     {
00252         UC_FIRM_TRACE("UCFM_EVENT_FINALIZE_ERROR");
00253         arm_uc_signal_ucfm_handler(error_event);
00254     }
00255 }
00256 
00257 /******************************************************************************/
00258 
00259 /* Function for decoupling PAL callbacks using the internal task queue. */
00260 /* Write commit done */
00261 static void event_handler_finalize(void)
00262 {
00263     UC_FIRM_TRACE("event_handler_finalize");
00264 
00265     /* setup mandatory hash */
00266     arm_uc_mdType_t mdtype = ARM_UC_CU_SHA256;
00267     arm_uc_error_t result = ARM_UC_cryptoHashSetup(&mdHandle, mdtype);
00268 
00269     if (result.error == ERR_NONE)
00270     {
00271         /* initiate hash calculation */
00272         package_offset = 0;
00273 
00274         /* indicate number of bytes needed */
00275         front_buffer->size = (package_configuration->package_size < front_buffer->size_max)?
00276                               package_configuration->package_size : front_buffer->size_max;
00277 
00278         /* initiate read from PAL */
00279         result = ARM_UCP_Read(package_configuration->package_id,
00280                               package_offset,
00281                               front_buffer);
00282     }
00283 
00284     if (result.error != ERR_NONE)
00285     {
00286         UC_FIRM_ERR_MSG("ARM_UC_cryptoHashSetup failed");
00287         arm_uc_signal_ucfm_handler(UCFM_EVENT_FINALIZE_ERROR);
00288     }
00289 }
00290 
00291 /* Function for decoupling PAL callbacks using the internal task queue. */
00292 static void event_handler_read(void)
00293 {
00294 #if UCFM_DEBUG_OUTPUT
00295     printf("event_handler_read: %" PRIX32 "\r\n", front_buffer->size);
00296 #endif
00297 
00298     /* check that read succeeded in reading data into buffer */
00299     if (front_buffer->size > 0)
00300     {
00301         /* check if read over shot */
00302         if ((package_offset + front_buffer->size) >
00303             package_configuration->package_size)
00304         {
00305             /* trim buffer */
00306             front_buffer->size = package_configuration->package_size - package_offset;
00307         }
00308 
00309         /* update offset and continue reading data from PAL */
00310         package_offset += front_buffer->size;
00311         arm_uc_internal_process_hash();
00312     }
00313     else
00314     {
00315         /* error - no data processed */
00316         UC_FIRM_TRACE("UCFM_EVENT_FINALIZE_ERROR");
00317         arm_uc_signal_ucfm_handler(UCFM_EVENT_FINALIZE_ERROR);
00318     }
00319 }
00320 
00321 static void arm_uc_signal_ucfm_handler(uint32_t event)
00322 {
00323     if (ucfm_handler)
00324     {
00325         ucfm_handler(event);
00326     }
00327 }
00328 
00329 static void arm_uc_internal_event_handler(uint32_t event)
00330 {
00331     switch (event)
00332     {
00333         case ARM_UC_PAAL_EVENT_FINALIZE_DONE:
00334             event_handler_finalize();
00335             break;
00336         case ARM_UC_PAAL_EVENT_READ_DONE:
00337             event_handler_read();
00338             break;
00339         default:
00340             /* pass all other events directly */
00341             arm_uc_signal_ucfm_handler(event);
00342             break;
00343     }
00344 }
00345 
00346 static void ARM_UCFM_PALEventHandler(uint32_t event)
00347 {
00348     /* decouple event handler from callback */
00349     ARM_UC_PostCallback(&arm_uc_event_handler_callback,
00350                         arm_uc_internal_event_handler, event);
00351 }
00352 
00353 /******************************************************************************/
00354 static arm_uc_error_t ARM_UCFM_Initialize(ARM_UCFM_SignalEvent_t handler)
00355 {
00356     UC_FIRM_TRACE("ARM_UCFM_Initialize");
00357 
00358     arm_uc_error_t result = (arm_uc_error_t){ FIRM_ERR_INVALID_PARAMETER };
00359 
00360     if (handler)
00361     {
00362         result = ARM_UCP_Initialize(ARM_UCFM_PALEventHandler);
00363 
00364         if (result.error == ERR_NONE)
00365         {
00366             ucfm_handler = handler;
00367         }
00368     }
00369 
00370     return result;
00371 }
00372 
00373 static arm_uc_error_t ARM_UCFM_Prepare(ARM_UCFM_Setup_t* configuration,
00374                                        const arm_uc_firmware_details_t* details,
00375                                        arm_uc_buffer_t* buffer)
00376 {
00377     UC_FIRM_TRACE("ARM_UCFM_Setup");
00378 
00379     arm_uc_error_t result = (arm_uc_error_t){ FIRM_ERR_NONE };
00380 
00381     /* sanity checks */
00382     if (!ucfm_handler)
00383     {
00384         UC_FIRM_ERR_MSG("Event handler not set. Should call Initialise before calling Setup");
00385         result =  (arm_uc_error_t){ FIRM_ERR_UNINITIALIZED };
00386     }
00387     /* check configuration is defined and contains key and iv. */
00388     else if ((!(configuration &&
00389               ((configuration->mode == UCFM_MODE_NONE_SHA_256) ||
00390                (configuration->key && configuration->iv)))) ||
00391              !buffer ||
00392              !buffer->ptr)
00393     {
00394         result =  (arm_uc_error_t){ FIRM_ERR_INVALID_PARAMETER };
00395     }
00396 
00397     /* allocate space using PAL */
00398     if (result.error == ERR_NONE)
00399     {
00400         result = ARM_UCP_Prepare(configuration->package_id,
00401                                  details,
00402                                  buffer);
00403 
00404         if (result.error != ERR_NONE)
00405         {
00406             UC_FIRM_ERR_MSG("ARM_UCP_Prepare failed");
00407         }
00408     }
00409 
00410     /* setup encryption if requested by mode */
00411     if ((result.error == ERR_NONE) &&
00412         (configuration->mode != UCFM_MODE_NONE_SHA_256))
00413     {
00414         /* A previously aborted firmware write will have left the cipherHandler
00415            in an inconsistent state. If the IV is not NULL, clear the context
00416            using the call to finish and set the struct to zero.
00417         */
00418         if (cipherHandle.aes_iv != NULL)
00419         {
00420             ARM_UC_cryptoDecryptFinish(&cipherHandle, buffer);
00421             memset(&cipherHandle, 0, sizeof(arm_uc_cipherHandle_t));
00422         }
00423 
00424         /* setup cipherHanlde with decryption keys */
00425         uint32_t bits = (configuration->mode == UCFM_MODE_AES_CTR_128_SHA_256) ? 128 : 256;
00426         result = ARM_UC_cryptoDecryptSetup(&cipherHandle,
00427                                            configuration->key,
00428                                            configuration->iv,
00429                                            bits);
00430 
00431         if (result.error != ERR_NONE)
00432         {
00433             UC_FIRM_ERR_MSG("ARM_UC_cryptoDecryptSetup failed in %" PRIu32 " bit mode", bits);
00434         }
00435     }
00436 
00437     /* Initialise the internal state */
00438     if (result.error == ERR_NONE)
00439     {
00440         package_configuration = configuration;
00441         package_offset = 0;
00442         ready_to_receive = true;
00443     }
00444 
00445     return result;
00446 }
00447 
00448 static arm_uc_error_t ARM_UCFM_Write(const arm_uc_buffer_t* fragment)
00449 {
00450     UC_FIRM_TRACE("ARM_UCFM_Write");
00451 
00452     arm_uc_error_t result = (arm_uc_error_t){ FIRM_ERR_NONE };
00453 
00454     if (!fragment || fragment->size_max == 0 || fragment->size > fragment->size_max || !fragment->ptr)
00455     {
00456         result = (arm_uc_error_t){ FIRM_ERR_INVALID_PARAMETER };
00457     }
00458     else if (!ready_to_receive)
00459     {
00460         result = (arm_uc_error_t){ FIRM_ERR_UNINITIALIZED };
00461     }
00462     else
00463     {
00464         /* decrypt fragment before writing to PAL */
00465         if (package_configuration->mode != UCFM_MODE_NONE_SHA_256)
00466         {
00467             /* temporary buffer for decrypting in place */
00468             uint8_t decrypt_output_ptr[2 * UCFM_MAX_BLOCK_SIZE];
00469             arm_uc_buffer_t decrypt_buffer = {
00470                 .size_max = sizeof(decrypt_output_ptr),
00471                 .size = 0,
00472                 .ptr = decrypt_output_ptr
00473             };
00474 
00475             uint32_t fragment_offset = 0;
00476             while (fragment_offset < fragment->size)
00477             {
00478                 /* default to max length */
00479                 uint32_t length_update = decrypt_buffer.size_max;
00480 
00481                 /* adjust size to not overshoot */
00482                 if (fragment_offset + length_update > fragment->size)
00483                 {
00484                     length_update = fragment->size - fragment_offset;
00485                 }
00486 
00487                 /* decrypt part of the fragment using the offset */
00488                 ARM_UC_cryptoDecryptUpdate(&cipherHandle,
00489                                            &fragment->ptr[fragment_offset],
00490                                            length_update,
00491                                            &decrypt_buffer);
00492 
00493 #if UCFM_DEBUG_OUTPUT
00494                 debug_output_decryption(&fragment->ptr[fragment_offset],
00495                                         &decrypt_buffer);
00496 #endif
00497 
00498                 /* overwrite the encrypted data with the decrypted data */
00499                 memcpy(&fragment->ptr[fragment_offset],
00500                        decrypt_buffer.ptr,
00501                        length_update);
00502 
00503                 /* update offset */
00504                 fragment_offset += length_update;
00505             }
00506         }
00507 
00508         /* store fragment using PAL */
00509         result = ARM_UCP_Write(package_configuration->package_id,
00510                                package_offset,
00511                                fragment);
00512 
00513         if (result.error == ERR_NONE)
00514         {
00515             package_offset += fragment->size;
00516         }
00517     }
00518 
00519     return result;
00520 }
00521 
00522 static arm_uc_error_t ARM_UCFM_Finalize(arm_uc_buffer_t* front, arm_uc_buffer_t* back)
00523 {
00524     UC_FIRM_TRACE("ARM_UCFM_Finish");
00525 
00526     arm_uc_error_t result = (arm_uc_error_t){ FIRM_ERR_NONE };
00527 
00528     if (!ready_to_receive)
00529     {
00530         result = (arm_uc_error_t){ FIRM_ERR_UNINITIALIZED };
00531     }
00532     else if ((front == NULL) ||
00533              (front != NULL && ((front->size_max % ARM_UC_SHA256_SIZE) != 0)) ||
00534              (back != NULL && ((back->size_max % ARM_UC_SHA256_SIZE) != 0)))
00535     {
00536         result = (arm_uc_error_t){ FIRM_ERR_INVALID_PARAMETER };
00537     }
00538     else
00539     {
00540         /* flush decryption buffer, discard data */
00541         ARM_UC_cryptoDecryptFinish(&cipherHandle, front);
00542         memset(&cipherHandle, 0, sizeof(arm_uc_cipherHandle_t));
00543 
00544         /* save buffers, checking if the buffers actually exist */
00545         front_buffer = front;
00546         back_buffer = (back == NULL) ? front_buffer : back;
00547 
00548         /* flush to PAL */
00549         result = ARM_UCP_Finalize(package_configuration->package_id);
00550 
00551         /* disable module until next setup call is received */
00552         ready_to_receive = false;
00553     }
00554 
00555     return result;
00556 }
00557 
00558 static arm_uc_error_t ARM_UCFM_Activate(uint32_t location)
00559 {
00560     UC_FIRM_TRACE("ARM_UCFM_Activate");
00561 
00562     arm_uc_error_t result = { .code = FIRM_ERR_ACTIVATE };
00563 
00564     if (ucfm_handler)
00565     {
00566         result = ARM_UCP_Activate(location);
00567     }
00568 
00569     return result;
00570 }
00571 
00572 static arm_uc_error_t ARM_UCFM_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details)
00573 {
00574     UC_FIRM_TRACE("ARM_UCFM_GetActiveFirmwareDetails");
00575 
00576     arm_uc_error_t result = { .code = FIRM_ERR_INVALID_PARAMETER };
00577 
00578     if (ucfm_handler && details)
00579     {
00580         result = ARM_UCP_GetActiveFirmwareDetails(details);
00581     }
00582 
00583     return result;
00584 }
00585 
00586 static arm_uc_error_t ARM_UCFM_GetFirmwareDetails(uint32_t location,
00587                                                   arm_uc_firmware_details_t* details)
00588 {
00589     UC_FIRM_TRACE("ARM_UCFM_GetFirmwareDetails");
00590 
00591     arm_uc_error_t result = { .code = FIRM_ERR_INVALID_PARAMETER };
00592 
00593     if (ucfm_handler && details)
00594     {
00595         result = ARM_UCP_GetFirmwareDetails(location, details);
00596     }
00597 
00598     return result;
00599 }
00600 
00601 static arm_uc_error_t ARM_UCFM_GetInstallerDetails(arm_uc_installer_details_t* details)
00602 {
00603     UC_FIRM_TRACE("ARM_UCFM_GetInstallerDetails");
00604 
00605     arm_uc_error_t result = { .code = FIRM_ERR_INVALID_PARAMETER };
00606 
00607     if (ucfm_handler && details)
00608     {
00609         result = ARM_UCP_GetInstallerDetails(details);
00610     }
00611 
00612     return result;
00613 }
00614 
00615 ARM_UC_FIRMWARE_MANAGER_t ARM_UC_FirmwareManager = {
00616     .Initialize               = ARM_UCFM_Initialize,
00617     .Prepare                  = ARM_UCFM_Prepare,
00618     .Write                    = ARM_UCFM_Write,
00619     .Finalize                 = ARM_UCFM_Finalize,
00620     .Activate                 = ARM_UCFM_Activate,
00621     .GetActiveFirmwareDetails = ARM_UCFM_GetActiveFirmwareDetails,
00622     .GetFirmwareDetails       = ARM_UCFM_GetFirmwareDetails,
00623     .GetInstallerDetails      = ARM_UCFM_GetInstallerDetails
00624 };