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