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