Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
esfs.c
00001 /* 00002 * Copyright (c) 2016 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 00018 00019 // ----------------------------------------------------------- Includes ----------------------------------------------------------- 00020 00021 #ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE 00022 #include MBED_CLOUD_CLIENT_USER_CONFIG_FILE 00023 #endif 00024 00025 00026 #include "pal.h" 00027 #include "esfs.h" 00028 #include "esfs_file_name.h" 00029 00030 #include "mbed-trace/mbed_trace.h" 00031 00032 00033 #include <string.h> // For memcmp and strncat 00034 00035 00036 00037 // --------------------------------------------------------- Definitions ---------------------------------------------------------- 00038 00039 00040 #define TRACE_GROUP "esfs" // Maximum 4 characters 00041 00042 // We do not really know what other uses (if any) the file system card will have. 00043 // We will assume that it may contain other files and we will keep all ESFS files in one directory. 00044 // A future enhancement could be to put files that are not to be removed at factory reset in a separate directory. 00045 #if !defined(ESFS_WORKING_DIRECTORY) 00046 #define ESFS_WORKING_DIRECTORY "WORKING" 00047 #endif 00048 00049 #if !defined(ESFS_BACKUP_DIRECTORY) 00050 #define ESFS_BACKUP_DIRECTORY "BACKUP" 00051 #endif 00052 00053 #define FACTORY_RESET_DIR "FR" 00054 #define FACTORY_RESET_FILE "fr_on" 00055 00056 // We choose a size that does not take up too much stack, but minimizes the number of reads. 00057 #define ESFS_READ_CHUNK_SIZE_IN_BYTES (64) 00058 00059 #define ESFS_BITS_IN_BYTE (8) 00060 #define ESFS_AES_BLOCK_SIZE_BYTES (16) 00061 #define ESFS_AES_IV_SIZE_BYTES (16) 00062 #define ESFS_AES_COUNTER_INDEX_IN_IV ESFS_AES_NONCE_SIZE_BYTES 00063 #define ESFS_AES_COUNTER_SIZE_BYTES (8) 00064 #define ESFS_AES_KEY_SIZE_BYTES (16) 00065 #define ESFS_AES_KEY_SIZE_BITS (ESFS_AES_KEY_SIZE_BYTES * ESFS_BITS_IN_BYTE) 00066 00067 // Defines the size in bytes of buffers for AES encryption / decryption. 00068 // In case we have to encrypt / decrypt a bigger amount of bytes, we loop over the buffer 00069 // and encrypt / decrypt up to ESFS_AES_BUF_SIZE_BYTES bytes on each step 00070 #define ESFS_AES_BUF_SIZE_BYTES (256) 00071 00072 // This should be incremented when the file format changes 00073 #define ESFS_FILE_FORMAT_VERSION (1) 00074 00075 #define ESFS_FILE_COPY_CHUNK_SIZE (256) 00076 00077 #define MAX_FULL_PATH_SIZE (PAL_MAX_FOLDER_DEPTH_CHAR + 1 + PAL_MAX(sizeof(ESFS_BACKUP_DIRECTORY), sizeof(ESFS_WORKING_DIRECTORY)) + PAL_MAX(sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE), ESFS_QUALIFIED_FILE_NAME_LENGTH)) 00078 00079 static bool esfs_initialize = false; 00080 00081 00082 00083 // -------------------------------------------------- Functions Implementation ---------------------------------------------------- 00084 00085 00086 // --------------------------------------------------------------- 00087 // Helper Functions 00088 // --------------------------------------------------------------- 00089 00090 00091 esfs_result_e esfs_init(void) 00092 { 00093 esfs_result_e result = ESFS_SUCCESS; 00094 tr_info("esfs_init - enter"); 00095 if (!esfs_initialize) 00096 { 00097 palStatus_t pal_result = PAL_SUCCESS; 00098 esfs_file_t file_handle = {0}; 00099 char dir_path[MAX_FULL_PATH_SIZE] = { 0 }; 00100 00101 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); 00102 if (pal_result != PAL_SUCCESS) 00103 { 00104 tr_err("esfs_init() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00105 result = ESFS_ERROR; 00106 goto errorExit; 00107 } 00108 00109 strncat(dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); 00110 00111 //Looping on first file system operation to work around IOTMORF-914 - sd-driver initialization 00112 for(int i=0 ; i<100; i++) 00113 { 00114 // Create the esfs subfolder working 00115 pal_result = pal_fsMkDir(dir_path); 00116 if ((pal_result == PAL_SUCCESS) || (pal_result == PAL_ERR_FS_NAME_ALREADY_EXIST)) 00117 break; 00118 tr_err("esfs_init() %d", i); 00119 pal_osDelay(50); 00120 00121 } 00122 00123 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST)) 00124 { 00125 tr_err("esfs_init() - pal_fsMkDir() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00126 result = ESFS_ERROR; 00127 goto errorExit; 00128 } 00129 00130 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); 00131 if (pal_result != PAL_SUCCESS) 00132 { 00133 00134 tr_err("esfs_init() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00135 result = ESFS_ERROR; 00136 goto errorExit; 00137 } 00138 00139 strncat(dir_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); 00140 00141 // Create the directory ESFS_BACKUP_DIRECTORY 00142 pal_result = pal_fsMkDir(dir_path); 00143 if (pal_result != PAL_SUCCESS) 00144 { 00145 // Any error apart from file exist returns error. 00146 if (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST) 00147 { 00148 tr_err("esfs_init() - pal_fsMkDir() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00149 result = ESFS_ERROR; 00150 goto errorExit; 00151 } 00152 } 00153 00154 // create the correct path for factory reset file fr_on 00155 strncat(dir_path, "/" FACTORY_RESET_DIR "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE)); 00156 pal_result = pal_fsFopen(dir_path, PAL_FS_FLAG_READONLY, &(file_handle.file)); 00157 // (res == PAL_SUCCESS) : flag file can be opened for reading --> file \FR\fr_on found 00158 // previous factory reset failed during execution 00159 // (res == PAL_ERR_FS_NO_FILE) : flag file was not found --> good scenario 00160 // (res != PAL_ERR_FS_NO_FILE) : file system problem 00161 if (pal_result == PAL_SUCCESS) 00162 { 00163 // Close the file before factory reset 00164 pal_result = pal_fsFclose(&(file_handle.file)); 00165 if (pal_result != PAL_SUCCESS) 00166 { 00167 tr_err("esfs_init() - unexpected filesystem behavior pal_fsFclose() failed with pal_status = 0x%x", (unsigned int)pal_result); 00168 result = ESFS_ERROR; 00169 goto errorExit; 00170 } 00171 // previous factory reset failed during execution - therefore we call this factory_reset again 00172 result = esfs_factory_reset(); 00173 if (result != ESFS_SUCCESS) 00174 { 00175 tr_err("esfs_init() - esfs_factory_reset() failed with esfs_result_e = 0x%x", result); 00176 result = ESFS_ERROR; 00177 goto errorExit; 00178 } 00179 } else if (pal_result != PAL_ERR_FS_NO_FILE) 00180 { 00181 tr_err("esfs_init() - unexpected filesystem behavior pal_fsFopen() failed with pal_status = 0x%x", (unsigned int)pal_result); 00182 result = ESFS_ERROR; 00183 goto errorExit; 00184 } 00185 00186 esfs_initialize = true; 00187 } 00188 return ESFS_SUCCESS; 00189 00190 errorExit: 00191 return result; 00192 00193 } 00194 00195 esfs_result_e esfs_finalize(void) 00196 { 00197 esfs_initialize = false; 00198 tr_info("esfs_finalize - enter"); 00199 return ESFS_SUCCESS; 00200 } 00201 00202 // Validate that a file handle has been initialized by create or open. 00203 // Parameters : file_handle - [IN] A pointer to a file handle for which we calculate the size. 00204 // Return : ESFS_SUCCESS on success. Error code otherwise 00205 static esfs_result_e esfs_validate(esfs_file_t *file_handle) 00206 { 00207 if(file_handle && file_handle->blob_name_length > 0) 00208 { 00209 return ESFS_SUCCESS; 00210 } 00211 else 00212 { 00213 return ESFS_ERROR; 00214 } 00215 } 00216 00217 00218 //Function : esfs_not_encrypted_file_header_size 00219 // 00220 //Description: This function returns the size in bytes of the file header without the metadata values part. 00221 // This is actually the non-encrypted part of the file header. 00222 // It is useful for calculation the file pointer position for AES encryption / decryption which starts only from the 00223 // encrypted part of the file. 00224 // 00225 //Parameters : file_handle - [IN] A pointer to a file handle for which we calculate the size. 00226 // 00227 //Return : The size in bytes of the non-encrypted part of the file header 00228 static size_t esfs_not_encrypted_file_header_size(esfs_file_t *file_handle) 00229 { 00230 esfs_tlv_properties_t *tlv_properties = &(file_handle->tlv_properties); 00231 00232 return ( file_handle->blob_name_length + // Name length field 00233 sizeof(file_handle->blob_name_length) + // Name field 00234 sizeof(uint16_t) + // Version field 00235 sizeof(uint16_t) + // Mode field 00236 (((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) ? ESFS_AES_NONCE_SIZE_BYTES : 0) + // Nonce field [non mandatory field] 00237 sizeof(tlv_properties->number_of_items) + // Metadata number of elements field 00238 (tlv_properties->number_of_items * sizeof(tlv_properties->tlv_items[0])) // Metadata tlv headers 00239 ); 00240 } 00241 00242 // Returns the size in bytes of the file header. 00243 // This can only be called after the header has been read. 00244 // Parameters : 00245 // file_handle - [IN] A pointer to a file handle for which we calculate the size. 00246 static size_t esfs_file_header_size(esfs_file_t *file_handle) 00247 { 00248 size_t metadata_size = 0; 00249 esfs_tlv_properties_t *tlv_properties = &file_handle->tlv_properties; 00250 00251 for(int i = 0; i < tlv_properties->number_of_items; i++) 00252 { 00253 metadata_size += tlv_properties->tlv_items[i].length_in_bytes; 00254 } 00255 00256 return esfs_not_encrypted_file_header_size(file_handle) + metadata_size; 00257 } 00258 00259 // Helper function to calculate the cmac on data that is written. 00260 // Parameters : 00261 // pbuf - [IN] A pointer to a buffer 00262 // num_bytes [IN] number of bytes that we request to write. 00263 // file_handle - [IN] A pointer to a file handle for which we calculate the size. 00264 // Return : ESFS_SUCCESS on success. Error code otherwise 00265 static esfs_result_e esfs_fwrite_and_calc_cmac(const void *pbuf, size_t num_bytes, esfs_file_t *file_handle) 00266 { 00267 palStatus_t res = pal_CMACUpdate(file_handle->signature_ctx, pbuf, num_bytes); 00268 if(res != PAL_SUCCESS) 00269 { 00270 tr_err("esfs_fwrite_and_calc_cmac() - pal_CMACUpdate failed with result = 0x%x", (unsigned int)res); 00271 return ESFS_ERROR; 00272 } 00273 00274 size_t num_bytes_written; 00275 res = pal_fsFwrite(&file_handle->file, pbuf, num_bytes, &num_bytes_written); 00276 if(res != PAL_SUCCESS || num_bytes != num_bytes_written) 00277 { 00278 tr_err("esfs_fwrite_and_calc_cmac() - pal_fsFwrite failed, status = 0x%x, written bytes = %zu, expected = %zu", 00279 (unsigned int)res, num_bytes_written, num_bytes); 00280 return ESFS_ERROR; 00281 } 00282 00283 return ESFS_SUCCESS; 00284 } 00285 00286 00287 // Helper function to start a cmac run. 00288 // Moves the file position to the start of the file. 00289 // Parameters : 00290 // file_handle - [IN] A pointer to a file handle. 00291 // If successful it creates a cmac context which must be destroyed with a call to esfs_cmac_finish 00292 // Return : ESFS_SUCCESS on success. Error code otherwise. 00293 static esfs_result_e esfs_cmac_start(esfs_file_t *file_handle) 00294 { 00295 unsigned char key[ESFS_CMAC_SIZE_IN_BYTES]; 00296 00297 // Get CMAC key from PAL 00298 palStatus_t res = pal_osGetDeviceKey(palOsStorageSignatureKey128Bit , &key[0], ESFS_CMAC_SIZE_IN_BYTES); 00299 if(res != PAL_SUCCESS) 00300 { 00301 tr_err("esfs_start_cmac() - pal_osGetDeviceKey() failed with pal_status = 0x%x", (unsigned int)res); 00302 return ESFS_ERROR; 00303 } 00304 00305 // Start CMAC with the key. Initializes signature_ctx 00306 res = pal_CMACStart(&file_handle->signature_ctx, &key[0], 128, PAL_CIPHER_ID_AES); 00307 if(res != PAL_SUCCESS) 00308 { 00309 tr_err("esfs_start_cmac() - pal_CMACStart() failed with pal_status = 0x%x", (unsigned int)res); 00310 return ESFS_ERROR; 00311 } 00312 00313 // Seek to the start of the file 00314 res = pal_fsFseek(&file_handle->file, 0, PAL_FS_OFFSET_SEEKSET); 00315 if(res != PAL_SUCCESS) 00316 { 00317 tr_err("esfs_start_cmac() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); 00318 00319 // Clean up the cmac context 00320 size_t num_bytes; 00321 // Ignore error. Sets file_handle->signature_ctx to 0 on success 00322 (void)pal_CMACFinish(&file_handle->signature_ctx, &key[0], &num_bytes); 00323 return ESFS_ERROR; 00324 } 00325 00326 return ESFS_SUCCESS; 00327 } 00328 00329 // Helper function to read and calculate the cmac on data that is read. 00330 // The function will not update the cmac if there is no CMAC context in the file handle. 00331 // Updates the file position. 00332 // Parameters : 00333 // file_handle - [IN] A pointer to a file handle for which we calculate the cmac. 00334 // pbuf [OUT] A pointer to a buffer containing the data that is read. 00335 // num_bytes [IN] number of bytes that we request to read. 00336 // num_bytes_read[OUT] A pointer to a location in which will be written the number of bytes actually read. 00337 // Return : ESFS_SUCCESS on success. Error code otherwise 00338 static esfs_result_e esfs_cmac_read(esfs_file_t *file_handle, void *pbuf, size_t num_bytes, size_t *num_bytes_read) 00339 { 00340 palStatus_t res = pal_fsFread(&file_handle->file, pbuf, num_bytes, num_bytes_read); 00341 if(res != PAL_SUCCESS) 00342 { 00343 tr_err("esfs_cmac_read() - pal_fsFread failed with status = 0x%x", (unsigned int)res); 00344 return ESFS_ERROR; 00345 } 00346 00347 // Update the CMAC only if there is a context. (It is allowed to read the file without calculating CMAC if 00348 // it does not need to checked.) 00349 if(file_handle->signature_ctx) 00350 { 00351 res = pal_CMACUpdate(file_handle->signature_ctx, pbuf, *num_bytes_read); 00352 if(res != PAL_SUCCESS) 00353 { 00354 tr_err("esfs_cmac_read() - pal_CMACUpdate failed with status = 0x%x", (unsigned int)res); 00355 return ESFS_ERROR; 00356 } 00357 } 00358 00359 return ESFS_SUCCESS; 00360 } 00361 00362 00363 // Helper function to skip past a part of the file while calculating the cmac on the skipped data. 00364 // Updates the file position. 00365 // Parameters : 00366 // file_handle - [IN] A pointer to a file handle. 00367 // to [IN] The absolute position from the start of the file to which skip. 00368 // It must be greater than the current position and no longer that the file size. 00369 // Return : ESFS_SUCCESS on success. Error code otherwise. 00370 static esfs_result_e esfs_cmac_skip_to(esfs_file_t *file_handle, int32_t to) 00371 { 00372 // Get current position 00373 int32_t current_pos; 00374 palStatus_t res = pal_fsFtell(&file_handle->file, ¤t_pos); 00375 if (res != PAL_SUCCESS) 00376 { 00377 tr_err("esfs_cmac_skip_to() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 00378 return ESFS_ERROR; 00379 } 00380 00381 // Iterate over the rest of file in chunks to calculate the cmac 00382 // buffer will contain only data read form the file 00383 for (int32_t i = to - current_pos; i > 0; i -= ESFS_READ_CHUNK_SIZE_IN_BYTES) 00384 { 00385 // Read a chunk 00386 // Here we read the file as is - plain text or encrypted 00387 uint8_t buffer[ESFS_READ_CHUNK_SIZE_IN_BYTES]; 00388 size_t num_bytes; 00389 esfs_result_e res = esfs_cmac_read(file_handle, buffer, PAL_MIN(i, ESFS_READ_CHUNK_SIZE_IN_BYTES), &num_bytes); 00390 if (res != ESFS_SUCCESS || num_bytes == 0) 00391 { 00392 tr_err("esfs_cmac_skip_to() failed num_bytes bytes = %zu", num_bytes); 00393 return ESFS_ERROR; 00394 } 00395 } 00396 return ESFS_SUCCESS; 00397 } 00398 00399 // Helper function to terminate a cmac run and return the resulting cmac. 00400 // Parameters : 00401 // file_handle - [IN] A pointer to a file handle for which we calculate the cmac. 00402 // pcmac [OUT] A pointer to a buffer into which the cmac will be written. It must be at least ESFS_CMAC_SIZE_IN_BYTES. 00403 // Return : ESFS_SUCCESS on success. Error code otherwise 00404 static esfs_result_e esfs_cmac_finish(esfs_file_t *file_handle, unsigned char *pcmac) 00405 { 00406 size_t num_bytes; 00407 00408 // Sets file_handle->signature_ctx to 0 on success 00409 palStatus_t res = pal_CMACFinish(&file_handle->signature_ctx, pcmac, &num_bytes); 00410 if(res != PAL_SUCCESS) 00411 { 00412 tr_err("esfs_finish_cmac() - pal_CMACFinish() failed with pal_status = 0x%x", (unsigned int)res); 00413 return ESFS_ERROR; 00414 } 00415 return ESFS_SUCCESS; 00416 } 00417 00418 // Helper function to compare the passed cmac against the one in the file and to the one in the file descriptor 00419 // and then return the file position in the passed value. 00420 // Updates the file position. 00421 // Parameters : 00422 // file_handle - [IN] A pointer to a file handle for which we check the cmac. 00423 // pcmac [IN] A pointer to a buffer containing the cmac that will be compared. It must be at least ESFS_CMAC_SIZE_IN_BYTES. 00424 // position [IN] The absolute position from the start of the file to which we restore the file position. 00425 // Return : ESFS_SUCCESS on success. Error code otherwise. 00426 static esfs_result_e esfs_cmac_check_and_restore(esfs_file_t *file_handle, unsigned char *pcmac, int32_t position) 00427 { 00428 // Read the signature from the file 00429 unsigned char file_cmac[ESFS_CMAC_SIZE_IN_BYTES]; 00430 size_t num_bytes; 00431 palStatus_t res = pal_fsFread(&file_handle->file, &file_cmac[0], ESFS_CMAC_SIZE_IN_BYTES, &num_bytes); 00432 if (res != PAL_SUCCESS || num_bytes != ESFS_CMAC_SIZE_IN_BYTES) 00433 { 00434 tr_err("esfs_cmac_check_and_restore() - pal_fsFread() failed with pal result = 0x%x and num_bytes bytes = %zu", (unsigned int)res, num_bytes); 00435 return ESFS_ERROR; 00436 } 00437 // Compare the cmac that we read from the file with the one that is passed and check it against 00438 // the one recorded in esfs_open in order to verify that the file is the same as the one that was opened. 00439 if(memcmp(&file_cmac[0], pcmac, ESFS_CMAC_SIZE_IN_BYTES) != 0 || 00440 memcmp(&file_cmac[0], &file_handle->cmac[0], ESFS_CMAC_SIZE_IN_BYTES) != 0) 00441 { 00442 tr_err("esfs_cmac_check_and_restore() - cmac that we read from the file does not match the one that we calculated"); 00443 return ESFS_CMAC_DOES_NOT_MATCH; 00444 } 00445 00446 // Set the file position to the byte indicated by position. 00447 res = pal_fsFseek(&file_handle->file, position, PAL_FS_OFFSET_SEEKSET); 00448 if(res != PAL_SUCCESS) 00449 { 00450 tr_err("esfs_cmac_check_and_restore() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); 00451 return ESFS_ERROR; 00452 } 00453 00454 return ESFS_SUCCESS; 00455 } 00456 00457 //Function : esfs_memcpy_reverse 00458 // 00459 //Description: This function copies the first <len_bytes> bytes from input buffer <src_ptr> to output buffer <dest_ptr> in 00460 // reversed order (e.g. '1' '2' '3' data array will be copied as '3' '2' '1'). 00461 // Note: The function assumes that the memory areas of the input buffers src_ptr and dest_ptr do not overlap. 00462 // 00463 //Parameters : dest_ptr - [IN / OUT] A pointer to the destination buffer to which bytes will be copied. 00464 // src_ptr - [IN] A pointer to the source buffer from which bytes will be copied. 00465 // len_bytes - [IN] Number of bytes to be copied. 00466 // 00467 //Return : A pointer to the output buffer <dest_ptr> 00468 static void *esfs_memcpy_reverse(void *dest_ptr, const void *src_ptr, uint32_t len_bytes) 00469 { 00470 uint8_t *tmp_dest_ptr = (uint8_t *)dest_ptr; 00471 const uint8_t *tmp_src_ptr = (const uint8_t *)src_ptr; 00472 00473 00474 // Make the reverse copy 00475 while(len_bytes > 0) 00476 { 00477 *(tmp_dest_ptr++) = *(tmp_src_ptr + len_bytes - 1); 00478 len_bytes--; 00479 } 00480 00481 return dest_ptr; 00482 } 00483 00484 //Function : esfs_calc_file_pos_for_aes 00485 // 00486 //Description: This function calculates the file position for the purpose of AES encrypt / decrypt: 00487 // The returned position is relative to the beginning of the encrypted data. 00488 // The file is encrypted starting from the meta data part (the meta data values). 00489 // 00490 //Parameters : file_handle - [IN] A pointer to a file handle on which we calculate the position. 00491 // position - [OUT] A pointer to size_t to be filled in with the returned position. 00492 // 00493 //Return : ESFS_SUCCESS on success. Error code otherwise 00494 static esfs_result_e esfs_calc_file_pos_for_aes(esfs_file_t *file_handle, size_t *position) 00495 { 00496 palStatus_t pal_status = PAL_SUCCESS; 00497 00498 size_t non_encrypt_size = 0; 00499 00500 00501 *position = 0; 00502 00503 // Get current position inside the file 00504 pal_status = pal_fsFtell( &(file_handle->file), (int32_t *)position ); 00505 00506 if(pal_status != PAL_SUCCESS) 00507 { 00508 tr_err("esfs_calc_file_pos_for_aes() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)pal_status); 00509 return ESFS_ERROR; 00510 } 00511 00512 // Calculate non_encrypt_size to be subtracted from position 00513 non_encrypt_size = esfs_not_encrypted_file_header_size(file_handle); 00514 00515 if(*position < non_encrypt_size) 00516 { 00517 tr_err("esfs_calc_file_pos_for_aes() - Error. Position is in non encrypted part."); 00518 return ESFS_ERROR; 00519 } 00520 00521 00522 *position -= non_encrypt_size; 00523 00524 00525 return ESFS_SUCCESS; 00526 } 00527 00528 00529 //Function : esfs_set_counter_in_iv_by_file_pos 00530 // 00531 //Description: This function fills in the last 8 bytes of the IV [iv128_arr] with the counter calculated according to 00532 // the input position. 00533 // 00534 //Parameters : position - [IN] The position in the file when count starts from the encrypted data part (the meta data values). 00535 // iv128_arr - [IN/OUT] A 16 bytes buffer holding the IV. 00536 // First 8 bytes contain the NONCE, and last 8 bytes will be filled in with the counter. 00537 // 00538 //Return : ESFS_SUCCESS on success. Error code otherwise 00539 static void esfs_set_counter_in_iv_by_file_pos(size_t position, uint8_t *iv128_arr) 00540 { 00541 uint64_t counter = 0; 00542 00543 00544 // Calculate counter part of IV 00545 counter = (uint64_t)(position / ESFS_AES_BLOCK_SIZE_BYTES); 00546 00547 00548 // Copy the counter part to the IV 00549 #if BIG__ENDIAN == 1 00550 memcpy(iv128_arr + ESFS_AES_COUNTER_INDEX_IN_IV, &counter, ESFS_AES_COUNTER_SIZE_BYTES); 00551 #else 00552 esfs_memcpy_reverse(iv128_arr + ESFS_AES_COUNTER_INDEX_IN_IV, &counter, ESFS_AES_COUNTER_SIZE_BYTES); 00553 #endif 00554 } 00555 00556 00557 //Function : esfs_aes_enc_dec_by_file_pos 00558 // 00559 //Description: This function encrypts / decrypts data using AES-CTR. 00560 // This is the basic function used for AES encrypt / decrypt. 00561 // Due to the nature of AES-CTR which works on blocks, special handling is required in case the data in the file is not 00562 // on block boundaries. In this case we encrypt / decrypt this "partial block data" in a temporal buffer after copying 00563 // the data to the corresponding index inside this buffer. The rest of the data is being encrypted / decrypted normally. 00564 // 00565 //Parameters : aes_ctx - [IN] The per-initiated AES context. 00566 // buf_in - [IN] A buffer containing to data to be encrypted / decrypted. 00567 // buf_out - [OUT] A buffer to be filled in with the encrypted / decrypted data. 00568 // len_bytes - [IN] Number of bytes to encrypt / decrypt. 00569 // position - [IN] The position in the file when count starts from the encrypted data part (the meta data values). 00570 // nonce64_ptr - [IN] An 8 bytes buffer holding the NONCE part of the IV. 00571 // 00572 //Return : ESFS_SUCCESS on success. Error code otherwise 00573 static esfs_result_e esfs_aes_enc_dec_by_file_pos( palAesHandle_t aes_ctx, 00574 const uint8_t *buf_in, 00575 uint8_t *buf_out, 00576 size_t len_bytes, 00577 size_t position, 00578 uint8_t *nonce64_ptr 00579 ) 00580 { 00581 palStatus_t pal_status = PAL_SUCCESS; 00582 00583 uint8_t prev_remainder = 0; // Size in bytes of partial block PREVIOUSLY encrypted / decrypted 00584 uint8_t partial_block_size = 0; // Size in bytes of partial block for NEXT encrypt / decrypt 00585 00586 uint8_t partial_block_size_temp = 0; 00587 00588 uint8_t partial_block_in[ESFS_AES_BLOCK_SIZE_BYTES] = {0}; // Will contain data for next partial encrypt / decrypt 00589 uint8_t partial_block_out[ESFS_AES_BLOCK_SIZE_BYTES] = {0}; 00590 00591 uint8_t iv_arr[ESFS_AES_IV_SIZE_BYTES] = {0}; // Will contain nonce [bytes 0 - 7] and counter [bytes 8 - 15] 00592 00593 00594 // -------- partial_block_in: Size = block_size [16 bytes] 00595 // | 00596 // | 00597 // \|/ 00598 // 00599 // ----------------------------------------------------------------------------------------- 00600 // | | | | 00601 // | 0 ... 0 | Data copied form buf_in | 0 ... 0 | 00602 // | | | | 00603 // ----------------------------------------------------------------------------------------- 00604 // ^ ^ ^ 00605 // | | | 00606 // | | | 00607 // | | | 00608 // Size: prev_remainder | Size: might be 0 00609 // | 00610 // | 00611 // Size: partial_block_size 00612 // (might consume the buffer till its end) 00613 00614 00615 prev_remainder = (position % ESFS_AES_BLOCK_SIZE_BYTES); 00616 00617 partial_block_size_temp = ESFS_AES_BLOCK_SIZE_BYTES - prev_remainder; 00618 partial_block_size = PAL_MIN(partial_block_size_temp, len_bytes); 00619 00620 // Prepare partial_block_in: Copy data for next encrypt / decrypt from buf_in to partial_block_in 00621 memcpy(partial_block_in + prev_remainder, buf_in, partial_block_size); 00622 00623 // Prepare iv_arr: Copy nonce into bytes [0 - 7] of IV buffer 00624 memcpy(iv_arr, nonce64_ptr, ESFS_AES_NONCE_SIZE_BYTES); 00625 00626 // Prepare iv_arr: Set counter in bytes [8 - 15] of IV buffer 00627 esfs_set_counter_in_iv_by_file_pos(position, iv_arr); 00628 00629 00630 // Encrypt / decrypt partial block [run on entire block, and copy later only desired part) 00631 pal_status = pal_aesCTRWithZeroOffset(aes_ctx, partial_block_in, partial_block_out, ESFS_AES_BLOCK_SIZE_BYTES, iv_arr); 00632 00633 if(pal_status != PAL_SUCCESS) 00634 { 00635 tr_err("esfs_aes_enc_dec_by_file_pos() - pal_aesCTRWithZeroOffset() failed with pal_status = 0x%x", (unsigned int)pal_status); 00636 return ESFS_ERROR; 00637 } 00638 00639 // Copy partial_block_out to buf_out 00640 memcpy(buf_out, partial_block_out + prev_remainder, partial_block_size); 00641 00642 00643 // Encrypt / decrypt the rest of the data 00644 if(len_bytes > partial_block_size) 00645 { 00646 // Set updated counter in bytes [8 - 15] of IV buffer 00647 esfs_set_counter_in_iv_by_file_pos(position + partial_block_size, iv_arr); 00648 00649 pal_status = pal_aesCTRWithZeroOffset(aes_ctx, buf_in + partial_block_size, buf_out + partial_block_size, len_bytes - partial_block_size, iv_arr); 00650 00651 if(pal_status != PAL_SUCCESS) 00652 { 00653 tr_err("esfs_aes_enc_dec_by_file_pos() - pal_aesCTRWithZeroOffset() failed with pal_status = 0x%x", (unsigned int)pal_status); 00654 return ESFS_ERROR; 00655 } 00656 } 00657 00658 00659 return ESFS_SUCCESS; 00660 } 00661 00662 00663 //Function : esfs_read_and_decrypt 00664 // 00665 //Description: This function reads encrypted data from a file, decrypts it, and writes it into a buffer. 00666 // 00667 //Parameters : file_handle - [IN] A pointer to a file handle from which we read data. 00668 // buffer - [IN] The buffer to fill in with decrypted file data. 00669 // bytes_to_read - [IN] Number of bytes to read from the file. 00670 // read_bytes_ptr - [OUT] A pointer to size_t to be filled in with number of bytes actually read from the file. 00671 // 00672 //Return : ESFS_SUCCESS on success. Error code otherwise 00673 static esfs_result_e esfs_read_and_decrypt(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes_ptr) 00674 { 00675 esfs_result_e result = ESFS_SUCCESS; 00676 00677 size_t position = 0; 00678 00679 00680 // Get file pointer position for AES - Must be done before calling pal_fsFread() which modifies the file pointer position 00681 result = esfs_calc_file_pos_for_aes(file_handle, &position); 00682 00683 if(result != ESFS_SUCCESS) 00684 { 00685 tr_err("esfs_read_and_decrypt() - esfs_calc_file_pos_for_aes() failed with status = 0x%x", result); 00686 return result; 00687 } 00688 00689 00690 // Read file's encrypted data into buffer 00691 result = esfs_cmac_read(file_handle, buffer, bytes_to_read, read_bytes_ptr ); 00692 00693 if((result != ESFS_SUCCESS) || (*read_bytes_ptr != bytes_to_read)) 00694 { 00695 tr_err("esfs_read_and_decrypt() - esfs_cmac_read() failed with ESFS_status = 0x%x", (unsigned int)result); 00696 return ESFS_ERROR; 00697 } 00698 00699 00700 // AES decrypt in-place - decrypt the encrypted data inside buffer, into buffer [out parameter] 00701 result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer, buffer, bytes_to_read, position, file_handle->nonce); 00702 00703 if(result != ESFS_SUCCESS) 00704 { 00705 tr_err("esfs_read_and_decrypt() - esfs_aes_enc_dec_by_file_pos() failed with status = 0x%x", (unsigned int)result); 00706 return result; 00707 } 00708 00709 00710 return ESFS_SUCCESS; 00711 } 00712 00713 00714 //Function : esfs_encrypt_fwrite_and_calc_cmac 00715 // 00716 //Description: This function takes a plain text buffer, encrypts it, writes the encrypted data to a file, and updates the 00717 // CMAC signature. 00718 // 00719 // Since we cannot modify the data of the input buffer (const), this operation cannot be done in-place, so we need 00720 // to use another buffer for the encryption result. In order to avoid dynamically allocation, we use a buffer 00721 // of size ESFS_AES_BUF_SIZE_BYTES statically allocated on the stack. This forces us to encrypt and write in a loop - 00722 // each iteration encrypts and writes maximum size of ESFS_AES_BUF_SIZE_BYTES bytes. 00723 // 00724 //Parameters : buffer - [IN] The buffer to encrypt and write to the file. 00725 // bytes_to_write - [IN] The number of bytes to write. 00726 // file_handle - [IN] A pointer to a file handle to which we write the data. 00727 // 00728 //Return : ESFS_SUCCESS on success. Error code otherwise 00729 static esfs_result_e esfs_encrypt_fwrite_and_calc_cmac(const void *buffer, size_t bytes_to_write, esfs_file_t *file_handle) 00730 { 00731 esfs_result_e result = ESFS_SUCCESS; 00732 00733 size_t position = 0; 00734 size_t remaining_bytes_to_write = bytes_to_write; 00735 00736 const uint8_t *buffer_tmp_ptr = (uint8_t *)buffer; // Will point to the next reading point in buffer as we read it 00737 00738 uint8_t encrypted_data[ESFS_AES_BUF_SIZE_BYTES] = {0}; // Will hold encrypted data to be written to the file 00739 00740 00741 if(buffer == NULL) 00742 { 00743 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - Bad arguments error. Input buffer is NULL."); 00744 return ESFS_ERROR; 00745 } 00746 00747 00748 // Get file pointer position for AES - Must be done before calling esfs_fwrite_and_calc_cmac() which modifies the file pointer position 00749 result = esfs_calc_file_pos_for_aes(file_handle, &position); 00750 00751 if(result != ESFS_SUCCESS) 00752 { 00753 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_calc_file_pos_for_aes failed with result=0x%x", result); 00754 return result; 00755 } 00756 00757 00758 // On every iteration in the loop, encrypt ESFS_AES_BUF_SIZE_BYTES bytes, and write them to the file 00759 while(remaining_bytes_to_write >= ESFS_AES_BUF_SIZE_BYTES) 00760 { 00761 // AES encrypt into encrypted_data 00762 result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer_tmp_ptr, encrypted_data, ESFS_AES_BUF_SIZE_BYTES, position, file_handle->nonce); 00763 00764 if(result != ESFS_SUCCESS) 00765 { 00766 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_aes_enc_dec_by_file_pos failed with result=0x%x", result); 00767 return result; 00768 } 00769 00770 // Write the encrypted data to the file 00771 result = esfs_fwrite_and_calc_cmac(encrypted_data, ESFS_AES_BUF_SIZE_BYTES, file_handle); 00772 00773 if((result != ESFS_SUCCESS)) 00774 { 00775 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_fwrite_and_calc_cmac() status = 0x%x", (unsigned int)result); 00776 00777 // esfs_fwrite_and_calc_cmac() failed so we cannot be sure of the state of the file - mark the file as invalid 00778 file_handle->file_invalid = 1; 00779 00780 return ESFS_ERROR; 00781 } 00782 00783 position += ESFS_AES_BUF_SIZE_BYTES; 00784 buffer_tmp_ptr += ESFS_AES_BUF_SIZE_BYTES; 00785 00786 remaining_bytes_to_write -= ESFS_AES_BUF_SIZE_BYTES; 00787 } 00788 00789 00790 // AES encrypt the leftover of buffer 00791 if(remaining_bytes_to_write > 0) 00792 { 00793 // AES encrypt into encrypted_data 00794 result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer_tmp_ptr, encrypted_data, remaining_bytes_to_write, position, file_handle->nonce); 00795 00796 if(result != ESFS_SUCCESS) 00797 { 00798 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_aes_enc_dec_by_file_pos failed with result=0x%x", result); 00799 return result; 00800 } 00801 00802 00803 // Write the encrypted data to the file 00804 result = esfs_fwrite_and_calc_cmac(encrypted_data, remaining_bytes_to_write, file_handle); 00805 00806 if((result != ESFS_SUCCESS)) 00807 { 00808 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_fwrite_and_calc_cmac() status = 0x%x", (unsigned int)result); 00809 00810 // esfs_fwrite_and_calc_cmac() failed so we cannot be sure of the state of the file - mark the file as invalid 00811 file_handle->file_invalid = 1; 00812 00813 return ESFS_ERROR; 00814 } 00815 } 00816 00817 00818 return ESFS_SUCCESS; 00819 } 00820 00821 00822 esfs_result_e esfs_reset(void) 00823 { 00824 esfs_result_e result = ESFS_SUCCESS; 00825 palStatus_t pal_result = PAL_SUCCESS; 00826 char dir_path[MAX_FULL_PATH_SIZE] = { 0 }; 00827 tr_info("esfs_reset - enter"); 00828 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); 00829 if (pal_result != PAL_SUCCESS) 00830 { 00831 tr_err("esfs_reset() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00832 result = ESFS_ERROR; 00833 goto errorExit; 00834 } 00835 00836 strncat(dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); 00837 00838 00839 // delete the files in working dir 00840 pal_result = pal_fsRmFiles(dir_path); 00841 // the use case is that esfs folder may not exist 00842 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 00843 { 00844 tr_err("esfs_reset() - pal_fsRmFiles(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 00845 result = ESFS_ERROR; 00846 goto errorExit; 00847 } 00848 00849 // delete working directory 00850 pal_result = pal_fsRmDir(dir_path); 00851 if (pal_result != PAL_SUCCESS) 00852 { 00853 // Any error apart from dir not exist returns error. 00854 if ((pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 00855 { 00856 tr_err("esfs_reset() - pal_fsRmDir(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 00857 result = ESFS_ERROR; 00858 goto errorExit; 00859 } 00860 } 00861 00862 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); 00863 if (pal_result != PAL_SUCCESS) 00864 { 00865 00866 tr_err("esfs_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00867 result = ESFS_ERROR; 00868 goto errorExit; 00869 } 00870 00871 strncat(dir_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); 00872 00873 00874 // delete the files in backup dir 00875 pal_result = pal_fsRmFiles(dir_path); 00876 // the use case is that esfs folder may not exist 00877 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 00878 { 00879 tr_err("esfs_reset() - pal_fsRmFiles(ESFS_BACKUP_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 00880 result = ESFS_ERROR; 00881 goto errorExit; 00882 } 00883 00884 pal_result = pal_fsRmDir(dir_path); 00885 if (pal_result != PAL_SUCCESS) 00886 { 00887 // Any error apart from dir not exist returns error. 00888 if ((pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 00889 { 00890 tr_err("esfs_reset() - pal_fsRmDir(ESFS_BACKUP_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 00891 result = ESFS_ERROR; 00892 goto errorExit; 00893 } 00894 } 00895 00896 if (esfs_finalize() != ESFS_SUCCESS) 00897 { 00898 tr_err("esfs_reset() - esfs_finalize() failed"); 00899 result = ESFS_ERROR; 00900 goto errorExit; 00901 } 00902 00903 if (esfs_init() != ESFS_SUCCESS) 00904 { 00905 tr_err("esfs_reset() - esfs_init() failed"); 00906 result = ESFS_ERROR; 00907 goto errorExit; 00908 } 00909 00910 return ESFS_SUCCESS; 00911 00912 errorExit: 00913 return result; 00914 } 00915 00916 00917 esfs_result_e esfs_factory_reset(void) { 00918 palStatus_t pal_result = PAL_SUCCESS; 00919 esfs_result_e result = ESFS_SUCCESS; 00920 esfs_file_t file_handle = { 0 }; 00921 char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 }; 00922 char full_path_backup_dir[MAX_FULL_PATH_SIZE] = { 0 }; 00923 bool is_single_partition = true; 00924 00925 tr_info("esfs_factory_reset - enter"); 00926 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); 00927 if (pal_result != PAL_SUCCESS) 00928 { 00929 tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00930 return ESFS_ERROR; 00931 } 00932 00933 strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY "/" FACTORY_RESET_DIR, sizeof(ESFS_BACKUP_DIRECTORY) + sizeof(FACTORY_RESET_DIR)); 00934 // Create the factory reset subfolder - FR 00935 pal_result = pal_fsMkDir(full_path_backup_dir); 00936 if (pal_result != PAL_SUCCESS) 00937 { 00938 // Any error apart from file exist returns error. 00939 if (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST) 00940 { 00941 tr_err("esfs_factory_reset() - pal_fsMkDir(ESFS_BACKUP_DIRECTORY/FACTORY_RESET_DIR) failed with pal_status = 0x%x", (unsigned int)pal_result); 00942 result = ESFS_ERROR; 00943 goto errorExit; 00944 } 00945 } 00946 00947 strncat(full_path_backup_dir, "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_FILE)); 00948 // Create the fr_on flag file 00949 pal_result = pal_fsFopen(full_path_backup_dir, PAL_FS_FLAG_READWRITEEXCLUSIVE, &(file_handle.file)); 00950 00951 // (res == PAL_SUCCESS) : factory reset is called on the first time 00952 // (res == PAL_ERR_FS_NAME_ALREADY_EXIST) : factory reset is called again after it was failed 00953 // on the first time and therefore the file exists 00954 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST)) 00955 { 00956 tr_err("esfs_factory_reset() - unexpected filesystem behavior pal_fsFopen() failed with pal_status = 0x%x", (unsigned int)pal_result); 00957 result = ESFS_ERROR; 00958 goto errorExit; 00959 } 00960 00961 // close the file only if we opened it 00962 if (pal_result == PAL_SUCCESS) 00963 { 00964 pal_result = pal_fsFclose(&(file_handle.file)); 00965 if (pal_result != PAL_SUCCESS) 00966 { 00967 tr_err("esfs_factory_reset() - unexpected filesystem behavior pal_fsFclose() failed with pal_status = 0x%x", (unsigned int)pal_result); 00968 result = ESFS_ERROR; 00969 goto errorExit; 00970 } 00971 } 00972 00973 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); 00974 if (pal_result != PAL_SUCCESS) 00975 { 00976 tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00977 result = ESFS_ERROR; 00978 goto errorExit; 00979 } 00980 00981 // Check if there is a single partition by comparing the primary and secondary mount points. 00982 // This is the only reliable way to do it, since the logic that determines the number of partitions is 00983 // hidden behind the PAL API. 00984 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); 00985 if (pal_result != PAL_SUCCESS) 00986 { 00987 tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00988 result = ESFS_ERROR; 00989 goto errorExit; 00990 } 00991 is_single_partition = (strcmp(working_dir_path,full_path_backup_dir) == 0); 00992 00993 strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); 00994 00995 // We can only format the working folder if it is dedicated for exclusive use of esfs and 00996 // it is not the only partition that exists. The assumption here is that if it is the only partition, 00997 // then the backup folder is also on that partition. In that case, formatting would remove the backup partition, 00998 // which we do not want to do! 00999 if (pal_fsIsPrivatePartition(PAL_FS_PARTITION_PRIMARY) && !is_single_partition) 01000 { 01001 pal_result = pal_fsFormat(PAL_FS_PARTITION_PRIMARY); 01002 if (pal_result != PAL_SUCCESS) 01003 { 01004 tr_err("esfs_factory_reset() - pal_fsFormat() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 01005 result = ESFS_ERROR; 01006 goto errorExit; 01007 } 01008 pal_result = pal_fsMkDir(working_dir_path); 01009 if (pal_result != PAL_SUCCESS) 01010 { 01011 tr_err("esfs_factory_reset() - pal_fsMkDir(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 01012 result = ESFS_ERROR; 01013 goto errorExit; 01014 } 01015 } 01016 else 01017 { 01018 // delete the files in working dir 01019 pal_result = pal_fsRmFiles(working_dir_path); 01020 // the use case is that esfs folder may not exist 01021 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 01022 { 01023 tr_err("esfs_factory_reset() - pal_fsRmFiles(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 01024 result = ESFS_ERROR; 01025 goto errorExit; 01026 } 01027 } 01028 01029 01030 01031 01032 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); 01033 if (pal_result != PAL_SUCCESS) 01034 { 01035 tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 01036 return ESFS_ERROR; 01037 } 01038 strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); 01039 01040 pal_result = pal_fsCpFolder(full_path_backup_dir, working_dir_path); 01041 01042 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE)) 01043 { 01044 tr_err("esfs_factory_reset() - pal_fsCpFolder() from backup to working failed with pal_status = 0x%x", (unsigned int)pal_result); 01045 result = ESFS_ERROR; 01046 goto errorExit; 01047 } 01048 01049 strncat(full_path_backup_dir, "/" FACTORY_RESET_DIR "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE)); 01050 // delete the flag file because factory reset flow ended successfully 01051 pal_result = pal_fsUnlink(full_path_backup_dir); 01052 if (pal_result != PAL_SUCCESS) 01053 { 01054 tr_err("esfs_factory_reset() - pal_fsUnlink(ESFS_BACKUP_DIRECTORY/FACTORY_RESET_DIR/FACTORY_RESET_FILE) failed with pal_status = 0x%x", (unsigned int)pal_result); 01055 result = ESFS_ERROR; 01056 goto errorExit; 01057 } 01058 01059 return ESFS_SUCCESS; 01060 01061 errorExit: 01062 return result; 01063 } 01064 01065 // Internal function to read header information and check its' validity. 01066 // Checks the name given against the name written in the file. 01067 // Checks the version. 01068 // Initializes some fields of file_handle: blob_name_length, esf_mode 01069 // Assumes that the read position is at the start of the file. 01070 // CMAC is calculated. 01071 // Parameters : 01072 // name [IN] A pointer to an array of binary data that uniquely identifies the file. 01073 // name_length [IN] size in bytes of the name. The minimum is 1 and the maximum is ESFS_MAX_NAME_LENGTH. 01074 // file_handle [IN] A pointer to a file handle on which we calculate the position. 01075 // return esf_success - name matches; 01076 // ESFS_HASH_CONFLICT - name does not match 01077 // ESFS_WRONG_FILE_VERSION - version does not match 01078 // ESFS_ERROR - other problem 01079 // On ESFS_SUCCESS or ESFS_HASH_CONFLICT the read position is set after the name. 01080 // On failure the position is undefined. 01081 static esfs_result_e esfs_check_file_validity(const uint8_t* name, size_t name_length, esfs_file_t *file_handle) 01082 { 01083 esfs_result_e result = ESFS_ERROR; 01084 01085 // Read the version 01086 uint16_t version; 01087 size_t num_bytes; 01088 result = esfs_cmac_read(file_handle, &version , sizeof(version), &num_bytes); 01089 if (result != ESFS_SUCCESS || num_bytes != sizeof(version)) 01090 { 01091 tr_err("esfs_check_file_validity() - esfs_cmac_read() failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01092 (unsigned int)result, num_bytes); 01093 goto errorExit; 01094 } 01095 // Check that the files version is the same as the source code version. 01096 if(version != ESFS_FILE_FORMAT_VERSION) 01097 { 01098 tr_err("esfs_check_file_validity() - invalid version: failed with version = %u instead of %u", (unsigned int)version, (unsigned int)ESFS_FILE_FORMAT_VERSION); 01099 result = ESFS_INVALID_FILE_VERSION; 01100 goto errorExit; 01101 } 01102 01103 // Read the mode 01104 result = esfs_cmac_read(file_handle, (void *)( &file_handle->esfs_mode ), sizeof(file_handle->esfs_mode), &num_bytes); 01105 if (result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->esfs_mode)) 01106 { 01107 tr_err("esfs_check_file_validity() mode - failed num_bytes bytes = %zu", num_bytes); 01108 goto errorExit; 01109 } 01110 // The mode is not used further in the opening process, so no further checks need be performed as cmac check will detect any 01111 // tampering. 01112 01113 // Read the name length 01114 result = esfs_cmac_read(file_handle, (void *)( &file_handle->blob_name_length ), sizeof(file_handle->blob_name_length), &num_bytes); 01115 if (result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->blob_name_length)) 01116 { 01117 tr_err("esfs_check_file_validity() name length- esfs_cmac_read() failed with result = 0x%x and num_bytes bytes = %zu", 01118 (unsigned int)result, num_bytes); 01119 goto errorExit; 01120 } 01121 // Check that the name in the file is the same length as the one given. It cannot be greater than ESFS_MAX_NAME_LENGTH 01122 // because that is checked on entry to the function. 01123 if (name_length != file_handle->blob_name_length) 01124 { 01125 tr_err("esfs_check_file_validity() - name length conflict"); 01126 // The hash of the name conflicts with the hash of another name. 01127 result = ESFS_HASH_CONFLICT; 01128 goto errorExit; 01129 } 01130 // Check the name chunk by chunk 01131 for (int i = name_length; i > 0; i -= ESFS_READ_CHUNK_SIZE_IN_BYTES) 01132 { 01133 // Read a chunk 01134 char buffer[ESFS_READ_CHUNK_SIZE_IN_BYTES]; 01135 result = esfs_cmac_read(file_handle, (void *)buffer, PAL_MIN(i, ESFS_READ_CHUNK_SIZE_IN_BYTES), &num_bytes); 01136 if (result != ESFS_SUCCESS || num_bytes == 0) 01137 { 01138 tr_err("esfs_check_file_validity() - read name failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01139 (unsigned int)result, num_bytes); 01140 goto errorExit; 01141 } 01142 // Check that the chunk matches 01143 //tr_info("Comparing %s (%d bytes) name_length=%d", name, (int )num_bytes,(int )name_length); 01144 if (memcmp(buffer, name, num_bytes) != 0) 01145 { 01146 tr_err("esfs_check_file_validity() - esfs hash conflict : The hash of the name conflicts with the hash of another name"); 01147 // The hash of the name conflicts with the hash of another name. 01148 result = ESFS_HASH_CONFLICT; 01149 goto errorExit; 01150 } 01151 // Advance past what we just checked. 01152 name += num_bytes; 01153 } 01154 return ESFS_SUCCESS; 01155 errorExit: 01156 return result; 01157 } 01158 01159 // Internal function to check the name against the name written in the file. 01160 // Assume that the read position is set to before the name length. 01161 // Parameters : 01162 // fd - [IN] A pointer to a file descriptor. 01163 // file_size [OUT] A pointer to a value into which the file size is returned. 01164 // return esf_success - name matches; 01165 // ESFS_HASH_CONFLICT - name does not match ; 01166 // ESFS_ERROR - other problem 01167 // On ESFS_SUCCESS or ESFS_HASH_CONFLICT the read position is set after the name. 01168 // On failure the position is undefined. 01169 01170 // Helper function 01171 // Restores current position unless it fails. 01172 // On failure the position is undefined. 01173 static palStatus_t esfs_get_physical_file_size(palFileDescriptor_t* fd, int32_t *file_size) 01174 { 01175 palStatus_t res; 01176 01177 // Get current position 01178 int32_t current_pos; 01179 res = pal_fsFtell(fd, ¤t_pos); 01180 if (res != PAL_SUCCESS) 01181 { 01182 tr_err("esfs_get_physical_file_size() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 01183 goto errorExit; 01184 } 01185 // Seek to end of file 01186 res = pal_fsFseek(fd, 0, PAL_FS_OFFSET_SEEKEND); 01187 if (res != PAL_SUCCESS) 01188 { 01189 tr_err("esfs_get_physical_file_size() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); 01190 goto errorExit; 01191 } 01192 // Get new position 01193 res = pal_fsFtell(fd, file_size); 01194 if (res != PAL_SUCCESS) 01195 { 01196 tr_err("esfs_get_physical_file_size() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 01197 goto errorExit; 01198 } 01199 // Restore old position 01200 res = pal_fsFseek(fd, current_pos, PAL_FS_OFFSET_SEEKSET); 01201 if (res != PAL_SUCCESS) 01202 { 01203 tr_err("esfs_get_physical_file_size() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); 01204 goto errorExit; 01205 } 01206 01207 errorExit: 01208 return res; 01209 } 01210 01211 // Copy one file to another. 01212 // Parameters : 01213 // src_file [IN] A pointer to a string containing the source file name. 01214 // src_file [IN] A pointer to a string containing the destination file name. 01215 // Return : ESFS_SUCCESS on success. Error code otherwise 01216 static esfs_result_e esfs_copy_file(const char *src_file, const char *dst_file) 01217 { 01218 bool is_src_file_opened = false; 01219 bool is_dst_file_opened = false; 01220 esfs_file_t file_handle = { 0 }; 01221 esfs_file_t file_handle_copy = { 0 }; 01222 esfs_result_e result = ESFS_ERROR; 01223 palStatus_t res = PAL_SUCCESS; 01224 size_t bytes_to_read = ESFS_FILE_COPY_CHUNK_SIZE; 01225 size_t num_bytes_read = 0; 01226 size_t num_bytes_write = 0; 01227 uint8_t buffer[ESFS_FILE_COPY_CHUNK_SIZE] = {0}; 01228 int32_t file_size = 0; 01229 int32_t copied_bytes = 0; 01230 // Open src file read only mode 01231 res = pal_fsFopen(src_file, PAL_FS_FLAG_READONLY, &(file_handle.file)); 01232 if (res != PAL_SUCCESS) 01233 { 01234 // File cannot be opened so return an error 01235 tr_err("esfs_copy_file() - pal_fsFopen() src file failed with pal_status = 0x%x", (unsigned int)res); 01236 result = ESFS_NOT_EXISTS; 01237 goto errorExit; 01238 } 01239 is_src_file_opened = true; 01240 // Open for reading and writing exclusively, If the file already exists, trunced file 01241 res = pal_fsFopen(dst_file, PAL_FS_FLAG_READWRITETRUNC, &(file_handle_copy.file)); 01242 if (res != PAL_SUCCESS) 01243 { 01244 // File cannot be opened so return an error 01245 tr_err("esfs_copy_file() - pal_fsFopen() dst file failed with pal_status = 0x%x", (unsigned int)res); 01246 result = ESFS_ERROR; 01247 goto errorExit; 01248 } 01249 is_dst_file_opened = true; 01250 01251 res = esfs_get_physical_file_size(&(file_handle.file), &file_size); 01252 if (res != PAL_SUCCESS) 01253 { 01254 tr_err("esfs_copy_file() - esfs_get_physical_file_size() failed with pal_status = 0x%x", (unsigned int)res); 01255 result = ESFS_ERROR; 01256 goto errorExit; 01257 } 01258 while (copied_bytes < file_size) 01259 { 01260 if (copied_bytes + (int32_t)bytes_to_read > file_size) 01261 { 01262 bytes_to_read = file_size - copied_bytes; 01263 } 01264 res = pal_fsFread(&(file_handle.file), buffer, bytes_to_read, &num_bytes_read); 01265 if (res != PAL_SUCCESS) 01266 { 01267 tr_err("esfs_copy_file() - pal_fsFread() failed with pal_status = 0x%x", (unsigned int)res); 01268 result = ESFS_ERROR; 01269 goto errorExit; 01270 } 01271 01272 res = pal_fsFwrite(&(file_handle_copy.file), buffer, bytes_to_read, &num_bytes_write); 01273 if ((res != PAL_SUCCESS) || (num_bytes_write != bytes_to_read)) 01274 { 01275 tr_err("esfs_copy_file() - pal_fsFwrite() failed with pal result = 0x%x and num_bytes_write bytes = %zu", 01276 (unsigned int)res, num_bytes_write); 01277 result = ESFS_ERROR; 01278 goto errorExit; 01279 } 01280 01281 copied_bytes += bytes_to_read; 01282 01283 } 01284 01285 01286 res = pal_fsFclose(&(file_handle.file)); 01287 if (res != PAL_SUCCESS) 01288 { 01289 tr_err("esfs_copy_file() - pal_fsFclose() for src file failed with pal_status = 0x%x", (unsigned int)res); 01290 result = ESFS_ERROR; 01291 goto errorExit; 01292 } 01293 res = pal_fsFclose(&(file_handle_copy.file)); 01294 if (res != PAL_SUCCESS) 01295 { 01296 tr_err("esfs_copy_file() - pal_fsFclose() for dst file failed with pal_status = 0x%x", (unsigned int)res); 01297 result = ESFS_ERROR; 01298 goto errorExit; 01299 } 01300 return ESFS_SUCCESS; 01301 01302 errorExit: 01303 if (is_src_file_opened) 01304 { 01305 // we will not delete the src file 01306 pal_fsFclose(&(file_handle.file)); 01307 } 01308 01309 if (is_dst_file_opened) 01310 { 01311 pal_fsFclose(&(file_handle_copy.file)); 01312 // Clean up if possible. Ignore return value. 01313 (void)pal_fsUnlink(dst_file); 01314 } 01315 return result; 01316 } 01317 01318 01319 01320 01321 // Internal function to create a new file and open it for writing. 01322 // Does not return error if file exists. 01323 // Keep all the conditions that allow the file creation in a single function, esfs_create, while the 01324 // esfs_create_internal will concentrate on file creation mechanics. 01325 // Parameters: 01326 // name [IN] A pointer to an array of binary data that uniquely identifies the file. 01327 // name_length [IN] size in bytes of the name. The minimum is 1 and the maximum is ESFS_MAX_NAME_LENGTH. 01328 // meta_data [IN] A pointer to an array of TLVs structures with meta_data_qty members 01329 // meta_data_qty[IN] number of tlvs in the array pointed by meta_data parameter. Minimum is 0 maximum is ESFS_MAX_TYPE_LENGTH_VALUES 01330 // esfs_mode [IN] a bit map combination of values from enum EsfsMode. 01331 // file_handle [IN/OUT] Pointer to the handle data structure into which to write the new handle. 01332 // returns ESFS_SUCCESS The file handle can be used in other esfs functions. It must be closed to release it. 01333 // ESFS_ERROR - other problem 01334 static esfs_result_e esfs_create_internal( const uint8_t *name, 01335 size_t name_length, 01336 const esfs_tlv_item_t *meta_data, 01337 size_t meta_data_qty, 01338 uint16_t esfs_mode, 01339 esfs_file_t *file_handle, 01340 const char* full_path_to_create 01341 ) 01342 { 01343 esfs_result_e result = ESFS_ERROR; 01344 01345 int32_t position = 0; 01346 size_t i; 01347 uint16_t file_created = 0; 01348 uint16_t cmac_created = 0; 01349 uint16_t u16 = ESFS_FILE_FORMAT_VERSION; 01350 01351 01352 // Create the file. 01353 // Note that we always overwrite any previous file. 01354 palStatus_t res = pal_fsFopen(full_path_to_create, PAL_FS_FLAG_READWRITETRUNC, &file_handle->file); 01355 if(res != PAL_SUCCESS) 01356 { 01357 // more informative message will be written after hash conflict will be implemented 01358 tr_err("esfs_create_internal() - pal_fsFopen() failed with status 0x%x", (unsigned int)res); 01359 goto errorExit; 01360 } 01361 file_created = 1; 01362 01363 if(esfs_cmac_start(file_handle) != ESFS_SUCCESS) 01364 { 01365 goto errorExit; 01366 } 01367 cmac_created = 1; 01368 01369 // Write the version 01370 if(esfs_fwrite_and_calc_cmac(&u16, sizeof(u16), file_handle) != ESFS_SUCCESS) 01371 { 01372 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for esfs version failed"); 01373 result = ESFS_ERROR; 01374 goto errorExit; 01375 } 01376 01377 // Write the mode 01378 if(esfs_fwrite_and_calc_cmac(&esfs_mode, sizeof(esfs_mode), file_handle) != ESFS_SUCCESS) 01379 { 01380 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for esfs_mode failed"); 01381 result = ESFS_ERROR; 01382 goto errorExit; 01383 } 01384 01385 // Header 01386 // Write the name length 01387 u16 = (uint16_t)name_length; 01388 if(esfs_fwrite_and_calc_cmac(&u16, sizeof(u16), file_handle) != ESFS_SUCCESS) 01389 { 01390 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for name_length failed"); 01391 result = ESFS_ERROR; 01392 goto errorExit; 01393 } 01394 01395 // Write the name 01396 if(esfs_fwrite_and_calc_cmac(name, name_length, file_handle) != ESFS_SUCCESS) 01397 { 01398 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for name failed."); 01399 result = ESFS_ERROR; 01400 goto errorExit; 01401 } 01402 01403 // Write the AES nonce, whether the file is encrypted or not. This ensures that the file format is the same 01404 // whether encrypted or not. 01405 if ((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 01406 { 01407 if(esfs_fwrite_and_calc_cmac((void *)(file_handle->nonce), ESFS_AES_NONCE_SIZE_BYTES, file_handle) != ESFS_SUCCESS) 01408 { 01409 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for AES nonce failed"); 01410 result = ESFS_ERROR; 01411 goto errorExit; 01412 } 01413 } 01414 01415 // Write the Metadata header 01416 // Write the number of items of meta data 01417 u16 = (uint16_t)meta_data_qty; 01418 if(esfs_fwrite_and_calc_cmac(&u16,sizeof(u16), file_handle) != ESFS_SUCCESS) 01419 { 01420 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for number of items of meta data failed"); 01421 result = ESFS_ERROR; 01422 goto errorExit; 01423 } 01424 01425 // If there is meta data 01426 if(meta_data_qty != 0) 01427 { 01428 res = pal_fsFtell(&file_handle->file, &position); 01429 if(res != PAL_SUCCESS) 01430 { 01431 tr_err("esfs_create_internal() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 01432 result = ESFS_ERROR; 01433 goto errorExit; 01434 } 01435 position += (sizeof(file_handle->tlv_properties.tlv_items[0]) * meta_data_qty); 01436 for(i = 0; i < meta_data_qty; i++ ) 01437 { 01438 file_handle->tlv_properties.tlv_items[i].type = meta_data[i].type; 01439 file_handle->tlv_properties.tlv_items[i].length_in_bytes = meta_data[i].length_in_bytes; 01440 file_handle->tlv_properties.tlv_items[i].position = (uint16_t)position; 01441 // Increment position for next iteration 01442 position += meta_data[i].length_in_bytes; 01443 } 01444 01445 // Write the metadata items 01446 result = esfs_fwrite_and_calc_cmac(&file_handle->tlv_properties.tlv_items[0], sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty, file_handle); 01447 if(result != ESFS_SUCCESS) 01448 { 01449 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for meta data items failed with esfs result = 0x%x", result); 01450 result = ESFS_ERROR; 01451 goto errorExit; 01452 } 01453 01454 // Set the number_of_items field here since it is in use later in this function 01455 // when we calculate the file header size 01456 file_handle->tlv_properties.number_of_items = meta_data_qty; 01457 01458 // Write the Metadata data values 01459 // If encrypted esfs is requested (by the esfs_mode argument), then this part should be encrypted 01460 for(i = 0; i < meta_data_qty; i++ ) 01461 { 01462 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 01463 { 01464 result = esfs_encrypt_fwrite_and_calc_cmac(meta_data[i].value, meta_data[i].length_in_bytes, file_handle); 01465 } 01466 else 01467 { 01468 result = esfs_fwrite_and_calc_cmac(meta_data[i].value, meta_data[i].length_in_bytes, file_handle); 01469 } 01470 01471 if(result != ESFS_SUCCESS) 01472 { 01473 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for meta data item values failed with esfs result = 0x%x", result); 01474 result = ESFS_ERROR; 01475 goto errorExit; 01476 } 01477 } 01478 } 01479 01480 file_handle->file_flag = ESFS_WRITE; 01481 01482 return ESFS_SUCCESS; 01483 01484 errorExit: 01485 01486 if(file_created) 01487 { 01488 pal_fsFclose(&file_handle->file); 01489 // Clean up if possible. Ignore return value. 01490 (void)pal_fsUnlink(full_path_to_create); 01491 } 01492 if(cmac_created) 01493 { 01494 uint8_t key[ESFS_CMAC_SIZE_IN_BYTES]; 01495 // Clean up cmac. Ignore error. 01496 (void)esfs_cmac_finish(file_handle, &key[0]); 01497 } 01498 01499 return result; 01500 } 01501 01502 // --------------------------------------------------------------- 01503 // API Functions 01504 // --------------------------------------------------------------- 01505 01506 01507 esfs_result_e esfs_create(const uint8_t *name, size_t name_length, const esfs_tlv_item_t *meta_data, size_t meta_data_qty, uint16_t esfs_mode, esfs_file_t *file_handle) 01508 { 01509 01510 palStatus_t res = PAL_SUCCESS; 01511 esfs_result_e result = ESFS_ERROR; 01512 01513 bool is_aes_ctx_created = false; 01514 01515 01516 // Verify that the structure is always packed to six bytes, since we read and write it as a whole. 01517 PAL_ASSERT_STATIC(sizeof(esfs_tlvItem_t) == 6); 01518 01519 // Verify that the array is always packed without padding, since we read and write it as a whole. 01520 PAL_ASSERT_STATIC(sizeof(esfs_tlvItem_t[ESFS_MAX_TYPE_LENGTH_VALUES]) == ESFS_MAX_TYPE_LENGTH_VALUES * sizeof(esfs_tlvItem_t)); 01521 01522 tr_info("esfs_create - enter"); 01523 01524 // Check parameters 01525 if (!file_handle || !name || name_length == 0 || name_length > ESFS_MAX_NAME_LENGTH || meta_data_qty > ESFS_MAX_TYPE_LENGTH_VALUES) 01526 { 01527 tr_err("esfs_create() failed with bad parameters"); 01528 result = ESFS_INVALID_PARAMETER; 01529 goto errorExit; 01530 } 01531 01532 // Check the metadata parameter 01533 for(size_t meta_data_index = 0; meta_data_index < meta_data_qty; meta_data_index++ ) 01534 { 01535 if ((!meta_data[meta_data_index].value) || (meta_data[meta_data_index].length_in_bytes == 0)) 01536 { 01537 tr_err("esfs_create() failed with bad parameters for metadata"); 01538 result = ESFS_INVALID_PARAMETER; 01539 goto errorExit; 01540 } 01541 } 01542 01543 // If esfs is in encryption mode, make the required initializations 01544 if((esfs_mode & ESFS_ENCRYPTED) != 0) 01545 { 01546 // ** Create AES context for AES encryption 01547 res = pal_initAes( &(file_handle->aes_ctx) ); 01548 01549 if(res != PAL_SUCCESS) 01550 { 01551 tr_err("esfs_create() - pal_initAes() failed with pal status 0x%x", (unsigned int)res); 01552 result = ESFS_ERROR ; 01553 goto errorExit; 01554 } 01555 01556 is_aes_ctx_created = true; 01557 01558 // ** Get AES key from PAL 01559 // Note: On each call, PAL should return the same 128 bits key 01560 uint8_t aes_key[ESFS_AES_KEY_SIZE_BYTES]; // For AES encryption 01561 res = pal_osGetDeviceKey(palOsStorageEncryptionKey128Bit, aes_key, ESFS_AES_KEY_SIZE_BYTES); 01562 01563 if(res != PAL_SUCCESS) 01564 { 01565 tr_err("esfs_create() - pal_osGetDeviceKey() failed with pal status 0x%x", (unsigned int)res); 01566 result = ESFS_ERROR ; 01567 goto errorExit; 01568 } 01569 01570 // ** Assign generated AES key to AES context 01571 res = pal_setAesKey( file_handle->aes_ctx, 01572 aes_key, 01573 ESFS_AES_KEY_SIZE_BITS, 01574 PAL_KEY_TARGET_ENCRYPTION 01575 ); 01576 01577 if(res != PAL_SUCCESS) 01578 { 01579 tr_err("esfs_create() - pal_setAesKey() failed with pal status 0x%x", (unsigned int)res); 01580 result = ESFS_ERROR ; 01581 goto errorExit; 01582 } 01583 01584 // ** Generate the AES nonce for AES usage 01585 res = pal_osRandomBuffer(file_handle->nonce, ESFS_AES_NONCE_SIZE_BYTES); 01586 01587 if(res != PAL_SUCCESS) 01588 { 01589 tr_err("esfs_create() - pal_osRandomBuffer() failed with pal status 0x%x", (unsigned int)res); 01590 result = ESFS_ERROR ; 01591 goto errorExit; 01592 } 01593 } 01594 01595 // We set the blob_name_length field here because it is in use later in this function when we calculate the file header size. 01596 // Since this field is also used to check the file handle validity [ esfs_validate() ] we set it to zero on an error exit. 01597 file_handle->blob_name_length = name_length; 01598 01599 file_handle->esfs_mode = esfs_mode; 01600 01601 file_handle->file_invalid = 0; 01602 01603 file_handle->tlv_properties.number_of_items = 0; 01604 01605 // Indicate that there is not a signature context yet. 01606 file_handle->signature_ctx = 0; 01607 01608 file_handle->data_size = 0; 01609 01610 if (esfs_get_name_from_blob(name, name_length, file_handle->short_file_name, ESFS_FILE_NAME_LENGTH) != ESFS_SUCCESS) 01611 { 01612 tr_err("esfs_create() - esfs_get_name_from_blob() failed"); 01613 goto errorExit; 01614 } 01615 01616 // Put working file name in file_full_path 01617 char file_full_path[MAX_FULL_PATH_SIZE]; 01618 res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, file_full_path); 01619 if (res != PAL_SUCCESS) 01620 { 01621 tr_err("esfs_create() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); 01622 result = ESFS_ERROR; 01623 goto errorExit; 01624 } 01625 strncat(file_full_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); 01626 strncat(file_full_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 01627 01628 01629 // Check if the file exists in the working directory (not acceptable) 01630 // Note that this is just a check. We will only actually open the file later (in esfs_create_internal()). 01631 res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READONLY, &file_handle->file); 01632 if (res == PAL_SUCCESS) 01633 { 01634 result = ESFS_EXISTS; 01635 file_handle->esfs_mode = 0; 01636 // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION 01637 // Check if there is a different name in the file 01638 // Check that the name written inside the file is the same as that given. If not 01639 // you should choose a different name. 01640 esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle); 01641 if (check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION) 01642 { 01643 result = check_result; 01644 } 01645 pal_fsFclose(&file_handle->file); 01646 tr_err("esfs_create() - pal_fsFopen() for working dir file failed"); 01647 goto errorExit; 01648 } 01649 01650 // If factory reset file then we make some checks 01651 if (esfs_mode & (uint16_t)ESFS_FACTORY_VAL) 01652 { 01653 // Put backup folder name in file_full_path 01654 res = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, file_full_path); 01655 if (res != PAL_SUCCESS) 01656 { 01657 tr_err("esfs_create() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)res); 01658 result = ESFS_ERROR; 01659 goto errorExit; 01660 } 01661 strncat(file_full_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); 01662 01663 // Create the esfs subfolder for backup 01664 res = pal_fsMkDir(file_full_path); 01665 if (res != PAL_SUCCESS) 01666 { 01667 // Any error apart from file exist returns error. 01668 if (res != PAL_ERR_FS_NAME_ALREADY_EXIST) 01669 { 01670 tr_err("esfs_create() - pal_fsMkDir() for backup dir failed with pal status 0x%x", (unsigned int)res); 01671 goto errorExit; 01672 } 01673 } 01674 01675 // Put backup file name in file_full_path 01676 strcat(file_full_path, "/"); 01677 strncat(file_full_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 01678 01679 // Check if the file exists in esfs backup directory (acceptable unless there is a hash conflict for the name) 01680 res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READONLY, &file_handle->file); 01681 if (res == PAL_SUCCESS) 01682 { 01683 file_handle->esfs_mode = 0; 01684 // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION 01685 // Check if there is a different name in the file 01686 // Check that the name written inside the file is the same as that given. If not 01687 // you should choose a different name. 01688 esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle); 01689 01690 // Close the file. 01691 pal_fsFclose(&file_handle->file); 01692 01693 if (check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION) 01694 { 01695 tr_err("esfs_create() - esfs_check_file_validity() failed with status 0x%x", check_result); 01696 result = check_result; 01697 goto errorExit; 01698 } 01699 // It is OK for it to exist, so continue. 01700 } 01701 } 01702 01703 // Now we actually create the new file. 01704 // file_full_path contains the correct location (working/backup) 01705 result = esfs_create_internal( 01706 name, 01707 name_length, 01708 meta_data, 01709 meta_data_qty, 01710 esfs_mode, 01711 file_handle, 01712 // Working or backup 01713 file_full_path 01714 ); 01715 if(result != ESFS_SUCCESS) 01716 { 01717 goto errorExit; 01718 } 01719 01720 return ESFS_SUCCESS; 01721 01722 errorExit: 01723 01724 // Invalidate blob_name_length filed since it is used to check the file handle validity [ esfs_validate() ] 01725 if(file_handle != NULL) 01726 { 01727 file_handle->blob_name_length = 0; 01728 } 01729 01730 if(is_aes_ctx_created) 01731 { 01732 pal_freeAes( &(file_handle->aes_ctx) ); 01733 } 01734 return result; 01735 } 01736 01737 esfs_result_e esfs_open(const uint8_t *name, size_t name_length, uint16_t *esfs_mode, esfs_file_t *file_handle) 01738 { 01739 esfs_result_e result = ESFS_ERROR; 01740 uint16_t file_opened = 0; 01741 uint16_t cmac_created = 0; 01742 bool is_aes_ctx_created = false; 01743 palStatus_t res = PAL_SUCCESS; 01744 01745 tr_info("esfs_open - enter"); 01746 // Check parameters 01747 if(!file_handle || !name || name_length == 0 || name_length > ESFS_MAX_NAME_LENGTH) 01748 { 01749 tr_err("esfs_open() failed with bad parameters"); 01750 result = ESFS_INVALID_PARAMETER; 01751 goto errorExit; 01752 } 01753 01754 char working_dir_path[MAX_FULL_PATH_SIZE]; 01755 res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); 01756 if (res != PAL_SUCCESS) 01757 { 01758 tr_err("esfs_open() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); 01759 return ESFS_ERROR; 01760 } 01761 01762 strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); 01763 01764 // This is used to esfs_validate the file handle so we set it to zero here and only when open 01765 // succeeds to the real value. 01766 file_handle->blob_name_length = 0; 01767 01768 file_handle->file_invalid = 0; 01769 01770 memset(&file_handle->cmac[0], 0, sizeof(file_handle->cmac)); 01771 01772 if(esfs_get_name_from_blob(name, name_length, file_handle->short_file_name, ESFS_FILE_NAME_LENGTH) != ESFS_SUCCESS) 01773 { 01774 tr_err("esfs_open() - esfs_get_name_from_blob() failed"); 01775 result = ESFS_ERROR; 01776 goto errorExit; 01777 } 01778 01779 strncat(working_dir_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 01780 01781 // Open the file read only 01782 res = pal_fsFopen(working_dir_path, PAL_FS_FLAG_READONLY, &file_handle->file); 01783 if(res != PAL_SUCCESS) 01784 { 01785 // tr_err("esfs_open() - pal_fsFopen() for working dir file failed with pal_status = 0x%x", (unsigned int)res); 01786 // File cannot be opened so return an error 01787 result = ESFS_NOT_EXISTS; 01788 goto errorExit; 01789 } 01790 01791 file_opened = 1; 01792 01793 if(esfs_cmac_start(file_handle) != ESFS_SUCCESS) 01794 { 01795 goto errorExit; 01796 } 01797 cmac_created = 1; 01798 01799 // Check that the name written inside the file is the same as that given 01800 // Note: After this call, the read position will be set to the point after the "Name Blob" 01801 result = esfs_check_file_validity(name, name_length, file_handle); 01802 if(result != ESFS_SUCCESS) 01803 { 01804 // the requested file not exists, but exists file with the same short name 01805 if (result == ESFS_HASH_CONFLICT) 01806 { 01807 result = ESFS_NOT_EXISTS; 01808 } 01809 tr_err("esfs_open() - esfs_check_file_validity() failed with status = 0x%x", result); 01810 // File cannot be opened so return an error 01811 goto errorExit; 01812 } 01813 01814 if (esfs_mode) 01815 { 01816 *esfs_mode = file_handle->esfs_mode; // file_handle->esfs_mode was set by esfs_check_file_validity() 01817 } 01818 01819 // If esfs is in encryption mode, make the required initializations 01820 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 01821 { 01822 // ** Create AES context for AES decryption 01823 res = pal_initAes( &(file_handle->aes_ctx) ); 01824 01825 if(res != PAL_SUCCESS) 01826 { 01827 tr_err("esfs_open() - pal_initAes() failed with status 0x%x", (unsigned int)res); 01828 result = ESFS_ERROR ; 01829 goto errorExit; 01830 } 01831 01832 is_aes_ctx_created = true; 01833 01834 // ** Get AES key from PAL 01835 // Note: On each call, PAL should return the same 128 bits key 01836 uint8_t aes_key[ESFS_AES_KEY_SIZE_BYTES]; 01837 res = pal_osGetDeviceKey(palOsStorageEncryptionKey128Bit, aes_key, ESFS_AES_KEY_SIZE_BYTES); 01838 01839 if(res != PAL_SUCCESS) 01840 { 01841 tr_err("esfs_open() - pal_osGetDeviceKey() failed with status 0x%x", (unsigned int)res); 01842 result = ESFS_ERROR ; 01843 goto errorExit; 01844 } 01845 01846 // ** Assign generated AES key to AES context 01847 res = pal_setAesKey( file_handle->aes_ctx, 01848 aes_key, 01849 ESFS_AES_KEY_SIZE_BITS, 01850 PAL_KEY_TARGET_ENCRYPTION 01851 ); 01852 01853 if(res != PAL_SUCCESS) 01854 { 01855 tr_err("esfs_open() - pal_setAesKey() failed with status 0x%x", (unsigned int)res); 01856 result = ESFS_ERROR; 01857 goto errorExit; 01858 } 01859 01860 } 01861 01862 size_t num_bytes; 01863 01864 // ** Read the AES nonce into file_handle->nonce 01865 if ((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 01866 { 01867 result = esfs_cmac_read(file_handle, &file_handle->nonce[0], ESFS_AES_NONCE_SIZE_BYTES, &num_bytes); 01868 if((result != ESFS_SUCCESS) || (num_bytes != ESFS_AES_NONCE_SIZE_BYTES)) 01869 { 01870 tr_err("esfs_open() - esfs_cmac_read() (AES nonce) failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01871 (unsigned int)result, num_bytes); 01872 result = ESFS_ERROR; 01873 goto errorExit; 01874 } 01875 } 01876 01877 file_handle->tlv_properties.number_of_items = 0; 01878 01879 // Read the number of items of meta data 01880 uint16_t meta_data_qty; 01881 result = esfs_cmac_read(file_handle, (void *)( &meta_data_qty ), sizeof(meta_data_qty), &num_bytes); 01882 if(result != ESFS_SUCCESS || num_bytes != sizeof(meta_data_qty) || meta_data_qty > ESFS_MAX_TYPE_LENGTH_VALUES) 01883 { 01884 tr_err("esfs_open() - esfs_cmac_read() (number of items of meta data) failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01885 (unsigned int)result, num_bytes); 01886 result = ESFS_ERROR; 01887 goto errorExit; 01888 } 01889 01890 // Read the metadata properties if there are any 01891 if(meta_data_qty != 0) 01892 { 01893 result = esfs_cmac_read( file_handle, 01894 (void *) ( &(file_handle->tlv_properties.tlv_items[0]) ), 01895 (sizeof(file_handle->tlv_properties.tlv_items[0]) * meta_data_qty), 01896 &num_bytes 01897 ); 01898 01899 if(result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty) 01900 { 01901 tr_err("esfs_open() - esfs_cmac_read() (metadata properties) failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01902 (unsigned int)result, num_bytes); 01903 goto errorExit; 01904 } 01905 01906 // Skip to the start of the data by calculating the last metadata position plus its length 01907 esfs_tlvItem_t *ptypeLengthValueItem = &file_handle->tlv_properties.tlv_items[meta_data_qty - 1]; 01908 01909 if(esfs_cmac_skip_to(file_handle, ptypeLengthValueItem->position + ptypeLengthValueItem->length_in_bytes) != ESFS_SUCCESS) 01910 { 01911 tr_err("esfs_open() - esfs_cmac_skip_to() failed."); 01912 result = ESFS_ERROR; 01913 goto errorExit; 01914 } 01915 } 01916 01917 file_handle->tlv_properties.number_of_items = meta_data_qty; 01918 01919 // We are at the start of the data section 01920 file_handle->current_read_pos = 0; 01921 01922 // Get current position 01923 int32_t current_pos; 01924 res = pal_fsFtell(&file_handle->file, ¤t_pos); 01925 if (res != PAL_SUCCESS) 01926 { 01927 tr_err("esfs_open() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 01928 goto errorExit; 01929 } 01930 01931 // get the whole file size and store it in the handle 01932 res = esfs_get_physical_file_size(&file_handle->file, &file_handle->file_size); 01933 if (res != PAL_SUCCESS) 01934 { 01935 tr_err("esfs_open() - esfs_open() failed with status 0x%x", (unsigned int)res); 01936 result = ESFS_ERROR; 01937 goto errorExit; 01938 } 01939 01940 // Skip to the end of the file while calculating the cmac 01941 if(esfs_cmac_skip_to(file_handle, file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS) 01942 { 01943 tr_err("esfs_open() - esfs_cmac_skip_to() failed."); 01944 result = ESFS_ERROR; 01945 goto errorExit; 01946 } 01947 01948 // Terminate cmac calculation and get it. 01949 unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; 01950 if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS) 01951 { 01952 tr_err("esfs_open() - esfs_finish_cmac() failed"); 01953 goto errorExit; 01954 } 01955 cmac_created = 0; 01956 01957 // save the CMAC in the file descriptor. We will use this to check that the file has not 01958 // changed when esfs_read() or read_meta_data() is called. 01959 memcpy(&file_handle->cmac[0],&cmac[0],sizeof(file_handle->cmac)); 01960 01961 // Check the cmac and set the file position to the start of the data 01962 if(esfs_cmac_check_and_restore(file_handle, &cmac[0], current_pos) != ESFS_SUCCESS) 01963 { 01964 tr_err("esfs_open() - cmac that we read from the file does not match the one that we calculated"); 01965 result = ESFS_CMAC_DOES_NOT_MATCH; 01966 goto errorExit; 01967 } 01968 01969 // Calculate the size of the data only, by getting the file size and deducting the header and cmac 01970 file_handle->data_size = file_handle->file_size - esfs_file_header_size(file_handle); 01971 01972 // We deduct the cmac bytes at the end of the file since they are not part of the data 01973 file_handle->data_size -= ESFS_CMAC_SIZE_IN_BYTES; 01974 01975 file_handle->file_flag = ESFS_READ; 01976 file_handle->blob_name_length = name_length; 01977 01978 return ESFS_SUCCESS; 01979 01980 errorExit: 01981 if(file_opened) 01982 { 01983 pal_fsFclose(&file_handle->file); 01984 } 01985 if(is_aes_ctx_created) 01986 { 01987 pal_freeAes( &(file_handle->aes_ctx) ); 01988 } 01989 if(cmac_created) 01990 { 01991 // Clean up cmac. Ignore error. 01992 (void)esfs_cmac_finish(file_handle, &cmac[0]); 01993 } 01994 01995 return result; 01996 } 01997 01998 esfs_result_e esfs_write(esfs_file_t *file_handle, const void *buffer, size_t bytes_to_write) 01999 { 02000 esfs_result_e result = ESFS_ERROR; 02001 02002 tr_info("esfs_write - enter"); 02003 if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!buffer) || (bytes_to_write == 0)) 02004 { 02005 tr_err("esfs_write() failed with bad parameters"); 02006 return ESFS_INVALID_PARAMETER; 02007 } 02008 02009 if(file_handle->file_flag == ESFS_READ) 02010 { 02011 tr_err("esfs_write() write failed - file is opened for read only"); 02012 result = ESFS_FILE_OPEN_FOR_READ; 02013 goto errorExit; 02014 } 02015 else 02016 { 02017 // Write data 02018 // If encrypted esfs is requested (file_handle->esfs_mode), then this part should be encrypted 02019 02020 // The data should be encrypted if the encrypted esfs is requested by the esfs_mode argument 02021 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 02022 { 02023 result = esfs_encrypt_fwrite_and_calc_cmac(buffer, bytes_to_write, file_handle); 02024 } 02025 else 02026 { 02027 result = esfs_fwrite_and_calc_cmac(buffer, bytes_to_write, file_handle); 02028 } 02029 02030 if(result != ESFS_SUCCESS) 02031 { 02032 tr_err("esfs_write() - esfs_fwrite_and_calc_cmac()/esfs_encrypt_fwrite_and_calc_cmac() for data failed with esfs result = 0x%x", result); 02033 // Since the write failed, we cannot be sure of the state of the file, so we mark it as invalid. 02034 file_handle->file_invalid = 1; 02035 result = ESFS_ERROR; 02036 goto errorExit; 02037 } 02038 } 02039 02040 file_handle->data_size += bytes_to_write; 02041 02042 return ESFS_SUCCESS; 02043 02044 errorExit: 02045 return result; 02046 } 02047 02048 esfs_result_e esfs_read(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes) 02049 { 02050 esfs_result_e result = ESFS_ERROR; 02051 uint16_t cmac_created = 0; 02052 size_t remaining_bytes = 0; 02053 palStatus_t res = PAL_SUCCESS; 02054 02055 tr_info("esfs_read - enter"); 02056 if(esfs_validate(file_handle) != ESFS_SUCCESS || read_bytes == NULL || !buffer) 02057 { 02058 result = ESFS_INVALID_PARAMETER; 02059 goto errorExit; 02060 } 02061 02062 if(file_handle->file_flag != ESFS_READ) 02063 { 02064 result = ESFS_FILE_OPEN_FOR_WRITE; 02065 goto errorExit; 02066 } 02067 // Save file position 02068 int32_t position; 02069 res = pal_fsFtell(&file_handle->file, &position); 02070 if(res != PAL_SUCCESS) 02071 { 02072 tr_err("esfs_read() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res); 02073 goto errorExit; 02074 } 02075 02076 // Limit how many bytes we can actually read depending on the size of the data section. 02077 remaining_bytes = file_handle->data_size - file_handle->current_read_pos; 02078 bytes_to_read = PAL_MIN(remaining_bytes, bytes_to_read); 02079 02080 if(esfs_cmac_start(file_handle) != ESFS_SUCCESS) 02081 { 02082 goto errorExit; 02083 } 02084 cmac_created = 1; 02085 02086 if(esfs_cmac_skip_to(file_handle, position) != ESFS_SUCCESS) 02087 { 02088 goto errorExit; 02089 } 02090 02091 // Read data 02092 // If required according to esfs_mode, the read data will be decrypted 02093 size_t num_bytes; 02094 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 02095 { 02096 if(esfs_read_and_decrypt(file_handle, buffer, bytes_to_read, &num_bytes) != ESFS_SUCCESS) 02097 { 02098 goto errorExit; 02099 } 02100 } 02101 else 02102 { 02103 if(esfs_cmac_read(file_handle, buffer, bytes_to_read, &num_bytes ) != ESFS_SUCCESS) 02104 { 02105 goto errorExit; 02106 } 02107 } 02108 02109 *read_bytes = num_bytes; 02110 02111 if(esfs_cmac_skip_to(file_handle ,file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS) 02112 { 02113 goto errorExit; 02114 } 02115 02116 unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; 02117 if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS) 02118 { 02119 tr_err("esfs_read() - esfs_finish_cmac() failed"); 02120 goto errorExit; 02121 } 02122 cmac_created = 0; 02123 02124 // Check the cmac and set to the byte after the end of the data being read. 02125 if(esfs_cmac_check_and_restore(file_handle, &cmac[0], position + num_bytes) != ESFS_SUCCESS) 02126 { 02127 tr_err("esfs_read() - cmac that we read from the file does not match the one that we calculated"); 02128 result = ESFS_CMAC_DOES_NOT_MATCH; 02129 goto errorExit; 02130 } 02131 02132 // Update the current position 02133 file_handle->current_read_pos += num_bytes; 02134 02135 return ESFS_SUCCESS; 02136 02137 errorExit: 02138 tr_err("esfs_read errorExit result=0x%x", result); 02139 if(cmac_created) 02140 { 02141 // Clean up cmac. Ignore error and resulting cmac. 02142 (void)esfs_cmac_finish(file_handle, &cmac[0]); 02143 } 02144 02145 return result; 02146 } 02147 02148 esfs_result_e esfs_seek(esfs_file_t *file_handle, int32_t offset, esfs_seek_origin_e whence, uint32_t *position) 02149 { 02150 esfs_result_e result = ESFS_ERROR; 02151 palStatus_t res = PAL_SUCCESS; 02152 tr_info("esfs_seek - enter"); 02153 if(esfs_validate(file_handle) != ESFS_SUCCESS) 02154 { 02155 tr_err("esfs_seek() failed with bad parameters"); 02156 return ESFS_INVALID_PARAMETER; 02157 } 02158 02159 if(file_handle->file_flag != ESFS_READ) 02160 { 02161 tr_err("esfs_seek() seek failed - file is opened for write only"); 02162 result = ESFS_FILE_OPEN_FOR_WRITE; 02163 goto errorExit; 02164 } 02165 pal_fsOffset_t pal_whence; 02166 // ESFS whence enum values are in sync with those of pal 02167 if(whence == ESFS_SEEK_SET) 02168 { 02169 if(offset > (int32_t)file_handle->data_size || offset < 0) 02170 { 02171 tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_SET"); 02172 result = ESFS_INVALID_PARAMETER; 02173 goto errorExit; 02174 } 02175 // Add the offset to the start of the data 02176 offset += esfs_file_header_size(file_handle); 02177 pal_whence = PAL_FS_OFFSET_SEEKSET; 02178 } 02179 else if(whence == ESFS_SEEK_END) 02180 { 02181 if(offset < -(int32_t)file_handle->data_size || offset > 0) 02182 { 02183 tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_END"); 02184 result = ESFS_INVALID_PARAMETER; 02185 goto errorExit; 02186 } 02187 // Deduct the cmac size from the offset because it is located after the data section. 02188 offset -= ESFS_CMAC_SIZE_IN_BYTES; 02189 pal_whence = PAL_FS_OFFSET_SEEKEND; 02190 } 02191 else if(whence == ESFS_SEEK_CUR) 02192 { 02193 if(offset + file_handle->current_read_pos > (int32_t)file_handle->data_size || offset + (int32_t)file_handle->current_read_pos < 0) 02194 { 02195 tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_CUR"); 02196 result = ESFS_INVALID_PARAMETER; 02197 goto errorExit; 02198 } 02199 pal_whence = PAL_FS_OFFSET_SEEKCUR; 02200 } 02201 else 02202 { 02203 tr_err("esfs_seek() failed with bad parameters - wrong whence"); 02204 result = ESFS_INVALID_PARAMETER; 02205 goto errorExit; 02206 } 02207 res = pal_fsFseek(&file_handle->file, offset, pal_whence); 02208 if(res != PAL_SUCCESS) 02209 { 02210 tr_err("esfs_seek() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); 02211 goto errorExit; 02212 } 02213 // Get current position if position is not NULL 02214 if(position) 02215 { 02216 res = pal_fsFtell(&file_handle->file, (int32_t *)position); 02217 if(res != PAL_SUCCESS) 02218 { 02219 tr_err("esfs_seek() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res); 02220 goto errorExit; 02221 } 02222 02223 // Ignore the file header data 02224 *position -= esfs_file_header_size(file_handle); 02225 02226 // Update the current position 02227 file_handle->current_read_pos = *position; 02228 } 02229 02230 return ESFS_SUCCESS; 02231 02232 errorExit: 02233 return result; 02234 } 02235 02236 02237 esfs_result_e esfs_file_size(esfs_file_t *file_handle, size_t *size_in_bytes) 02238 { 02239 esfs_result_e result = ESFS_ERROR; 02240 02241 tr_info("esfs_file_size - enter"); 02242 if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!size_in_bytes)) 02243 { 02244 tr_err("esfs_file_size() failed with bad parameters"); 02245 result = ESFS_INVALID_PARAMETER; 02246 goto errorExit; 02247 } 02248 02249 *size_in_bytes = file_handle->data_size; 02250 02251 return ESFS_SUCCESS; 02252 02253 errorExit: 02254 return result; 02255 } 02256 02257 esfs_result_e esfs_close(esfs_file_t *file_handle) 02258 { 02259 uint16_t failed_to_write_CMAC = 0; 02260 uint16_t file_esfs_mode = 0; 02261 esfs_file_flag_e esfs_file_flag = 0; 02262 char esfs_short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH] = {0}; 02263 esfs_result_e result = ESFS_ERROR; 02264 char full_path_working_dir[MAX_FULL_PATH_SIZE]; 02265 palStatus_t res = PAL_SUCCESS; 02266 02267 tr_info("esfs_close - enter"); 02268 if(esfs_validate(file_handle) != ESFS_SUCCESS) 02269 { 02270 tr_err("esfs_close() failed with bad parameters"); 02271 result = ESFS_INVALID_PARAMETER; 02272 goto errorExit; 02273 } 02274 02275 res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_working_dir); 02276 if (res != PAL_SUCCESS) 02277 { 02278 tr_err("esfs_close() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); 02279 result = ESFS_ERROR; 02280 goto errorExit; 02281 } 02282 02283 strncat(full_path_working_dir, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); 02284 02285 02286 // Close AES context if needed 02287 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 02288 { 02289 pal_freeAes( &(file_handle->aes_ctx) ); 02290 } 02291 02292 esfs_file_flag = file_handle->file_flag; 02293 file_esfs_mode = file_handle->esfs_mode; 02294 strncpy(esfs_short_file_name, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 02295 02296 if(file_handle->file_flag == ESFS_WRITE) 02297 { 02298 unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; 02299 // Finish signature calculation 02300 if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS) 02301 { 02302 tr_err("esfs_close() - esfs_cmac_finish() failed"); 02303 goto errorExit; 02304 } 02305 // Write signature 02306 size_t bytes_written; 02307 res = pal_fsFwrite(&file_handle->file, &cmac[0], sizeof(cmac), &bytes_written); 02308 if(res != PAL_SUCCESS || sizeof(cmac) != bytes_written) 02309 { 02310 tr_err("esfs_close() - pal_fsFwrite() (signature) failed with pal result = 0x%x and bytes_written bytes = %zu", 02311 (unsigned int)res, bytes_written); 02312 // mark the file invalid on a failed write 02313 file_handle->file_invalid = 1; 02314 // Continue so that we delete the file, but we should return failure later 02315 failed_to_write_CMAC = 1; 02316 } 02317 } 02318 02319 res = pal_fsFclose(&file_handle->file); 02320 if(res == PAL_SUCCESS) 02321 { 02322 // Remove a file that is invalid. It may have become invalid due to a failed write. 02323 if(file_handle->file_invalid) 02324 { 02325 strncat(full_path_working_dir,file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 02326 02327 res = pal_fsUnlink(full_path_working_dir); 02328 if(res != PAL_SUCCESS) 02329 { 02330 tr_err("esfs_close() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)res); 02331 goto errorExit; 02332 } 02333 } 02334 } 02335 else 02336 { 02337 tr_err("esfs_close() - pal_fsFclose() failed with pal status 0x%x", (unsigned int)res); 02338 goto errorExit; 02339 } 02340 02341 if(failed_to_write_CMAC) 02342 { 02343 goto errorExit; 02344 } 02345 02346 02347 if ((file_esfs_mode & ESFS_FACTORY_VAL) && (esfs_file_flag == ESFS_WRITE) && !(file_handle->file_invalid)) 02348 { 02349 char full_path_backup_dir[MAX_FULL_PATH_SIZE] = { 0 }; 02350 02351 res = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); 02352 if (res != PAL_SUCCESS) 02353 { 02354 tr_err("esfs_close() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)res); 02355 result = ESFS_ERROR; 02356 goto errorExit; 02357 } 02358 02359 strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY "/", sizeof(ESFS_BACKUP_DIRECTORY) + 1); 02360 02361 strncat(full_path_working_dir, esfs_short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH -1); 02362 strncat(full_path_backup_dir, esfs_short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 02363 02364 if (esfs_copy_file(full_path_backup_dir, full_path_working_dir) != ESFS_SUCCESS) 02365 { 02366 tr_err("esfs_close() - esfs_copy_file() failed"); 02367 goto errorExit; 02368 } 02369 } 02370 02371 return ESFS_SUCCESS; 02372 errorExit: 02373 return result; 02374 } 02375 02376 esfs_result_e esfs_delete(const uint8_t *name, size_t name_length) 02377 { 02378 02379 palStatus_t pal_result = PAL_SUCCESS; 02380 char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 }; 02381 char short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH]; 02382 esfs_result_e result = ESFS_ERROR; 02383 02384 tr_info("esfs_delete - enter"); 02385 // Check parameters 02386 if(!name || name_length == 0) 02387 { 02388 tr_err("esfs_delete() failed with bad parameters"); 02389 result = ESFS_INVALID_PARAMETER; 02390 goto errorExit; 02391 } 02392 if(esfs_get_name_from_blob(name, name_length, short_file_name, ESFS_FILE_NAME_LENGTH ) != ESFS_SUCCESS) 02393 { 02394 tr_err("esfs_delete() - esfs_get_name_from_blob() failed"); 02395 goto errorExit; 02396 } 02397 tr_info("esfs_delete %s", short_file_name); 02398 02399 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); 02400 if (pal_result != PAL_SUCCESS) 02401 { 02402 tr_err("esfs_delete() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 02403 result = ESFS_ERROR; 02404 goto errorExit; 02405 } 02406 02407 strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); 02408 02409 // We do not verify that name is the actual name in the file because currently we do not allow the situation of hash 02410 // clash to arise. 02411 02412 strncat(working_dir_path,short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 02413 02414 tr_info("esfs_delete %s", working_dir_path); 02415 pal_result = pal_fsUnlink(working_dir_path); 02416 02417 if ((pal_result == PAL_ERR_FS_NO_FILE) || (pal_result == PAL_ERR_FS_NO_PATH)) 02418 { 02419 tr_err("esfs_delete() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)pal_result); 02420 result = ESFS_NOT_EXISTS; 02421 goto errorExit; 02422 } 02423 else if (pal_result != PAL_SUCCESS) 02424 { 02425 tr_err("esfs_delete() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)pal_result); 02426 goto errorExit; 02427 } 02428 02429 return ESFS_SUCCESS; 02430 errorExit: 02431 return result; 02432 } 02433 02434 esfs_result_e esfs_get_meta_data_properties(esfs_file_t *file_handle, esfs_tlv_properties_t **meta_data_properties) 02435 { 02436 esfs_result_e result = ESFS_ERROR; 02437 tr_info("esfs_get_meta_data_properties - enter"); 02438 if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!meta_data_properties)) 02439 { 02440 tr_err("esfs_get_meta_data_properties() failed with bad parameters"); 02441 result = ESFS_INVALID_PARAMETER; 02442 goto errorExit; 02443 } 02444 02445 if (file_handle->file_flag != ESFS_READ) 02446 { 02447 tr_err("esfs_get_meta_data_properties() failed - file is opened for write only"); 02448 result = ESFS_FILE_OPEN_FOR_WRITE; 02449 goto errorExit; 02450 } 02451 02452 *meta_data_properties = &file_handle->tlv_properties; 02453 return ESFS_SUCCESS; 02454 errorExit: 02455 return result; 02456 } 02457 02458 02459 esfs_result_e esfs_read_meta_data(esfs_file_t *file_handle, uint32_t index, esfs_tlv_item_t *meta_data) 02460 { 02461 esfs_result_e result = ESFS_ERROR; 02462 bool is_read_error = false; 02463 uint16_t cmac_created = 0; 02464 int32_t offset_to_restore = 0; 02465 palStatus_t res = PAL_SUCCESS; 02466 02467 tr_info("esfs_read_meta_data - enter"); 02468 if(esfs_validate(file_handle) != ESFS_SUCCESS || index >= ESFS_MAX_TYPE_LENGTH_VALUES || !meta_data || (file_handle->tlv_properties.tlv_items[index].length_in_bytes == 0)) 02469 { 02470 tr_err("esfs_read_meta_data() failed with bad parameters"); 02471 result = ESFS_INVALID_PARAMETER; 02472 goto errorExit; 02473 } 02474 02475 if(file_handle->file_flag != ESFS_READ) 02476 { 02477 tr_err("esfs_read_meta_data() failed - file is opened for write only"); 02478 result = ESFS_FILE_OPEN_FOR_WRITE; 02479 goto errorExit; 02480 } 02481 // Get current file position 02482 int32_t current_pos; 02483 res = pal_fsFtell(&file_handle->file, ¤t_pos); 02484 if(res != PAL_SUCCESS) 02485 { 02486 tr_err("esfs_read_meta_data() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res); 02487 goto errorExit; 02488 } 02489 02490 // Start the cmac calculation and position to the start of the file 02491 if(esfs_cmac_start(file_handle) != ESFS_SUCCESS) 02492 { 02493 goto errorExit; 02494 } 02495 cmac_created = 1; 02496 02497 // Skip to the meta-data position while calculating the cmac 02498 if(esfs_cmac_skip_to(file_handle, file_handle->tlv_properties.tlv_items[index].position) != ESFS_SUCCESS) 02499 { 02500 tr_err("esfs_read_meta_data() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); 02501 goto errorExit; 02502 } 02503 02504 // Read data 02505 // If required according to esfs_mode, the read data will be decrypted 02506 size_t num_bytes; 02507 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 02508 { 02509 if(esfs_read_and_decrypt( file_handle, 02510 meta_data->value, 02511 file_handle->tlv_properties.tlv_items[index].length_in_bytes, 02512 &num_bytes 02513 ) != ESFS_SUCCESS) 02514 { 02515 is_read_error = true; 02516 } 02517 } 02518 else 02519 { 02520 if(esfs_cmac_read(file_handle, meta_data->value, file_handle->tlv_properties.tlv_items[index].length_in_bytes, &num_bytes ) != ESFS_SUCCESS) 02521 { 02522 is_read_error = true; 02523 } 02524 } 02525 02526 if(is_read_error || (num_bytes != file_handle->tlv_properties.tlv_items[index].length_in_bytes)) 02527 { 02528 tr_err("esfs_read_meta_data() - read data failed is_read_error = %s and num_bytes = %zu", 02529 is_read_error ? "true" : "false", num_bytes); 02530 goto errorExit; 02531 } 02532 02533 // Skip to the end of the data section of the file. 02534 if(esfs_cmac_skip_to(file_handle ,file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS) 02535 { 02536 goto errorExit; 02537 } 02538 02539 // Return the cmac 02540 unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; 02541 if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS) 02542 { 02543 tr_err("esfs_read() - esfs_finish_cmac() failed"); 02544 goto errorExit; 02545 } 02546 cmac_created = 0; 02547 02548 // Before restoring old position, make sure offset_to_restore is not a negative number 02549 offset_to_restore = current_pos; 02550 if(offset_to_restore < 0) 02551 { 02552 tr_err("esfs_read_meta_data() failed - current_pos is negative"); 02553 goto errorExit; 02554 } 02555 02556 // Check the cmac and restore the file position to the saved position 02557 if(esfs_cmac_check_and_restore(file_handle, &cmac[0], offset_to_restore) != ESFS_SUCCESS) 02558 { 02559 tr_err("esfs_read_meta_data() - cmac that we read from the file does not match the one that we calculated"); 02560 result = ESFS_CMAC_DOES_NOT_MATCH; 02561 goto errorExit; 02562 } 02563 02564 // Update meta_data fields 02565 meta_data->type = file_handle->tlv_properties.tlv_items[index].type; 02566 meta_data->length_in_bytes = file_handle->tlv_properties.tlv_items[index].length_in_bytes; 02567 02568 return ESFS_SUCCESS; 02569 02570 errorExit: 02571 if(cmac_created) 02572 { 02573 // Clean up cmac. Ignore error. 02574 (void)esfs_cmac_finish(file_handle, &cmac[0]); 02575 } 02576 return result; 02577 }
Generated on Tue Jul 12 2022 19:01:34 by 1.7.2