Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 };
Generated on Mon Aug 29 2022 19:53:38 by
